1 /*
2  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
3  * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "evolution-config.h"
19 
20 #include <gtk/gtk.h>
21 #include <glib/gi18n-lib.h>
22 
23 #include "e-cal-shell-view-private.h"
24 
25 #include "calendar/gui/ea-calendar.h"
26 #include "calendar/gui/calendar-view.h"
27 
28 #include "e-cal-base-shell-sidebar.h"
29 #include "e-cal-shell-content.h"
30 #include "e-cal-shell-view.h"
31 
G_DEFINE_DYNAMIC_TYPE(ECalShellView,e_cal_shell_view,E_TYPE_CAL_BASE_SHELL_VIEW)32 G_DEFINE_DYNAMIC_TYPE (ECalShellView, e_cal_shell_view, E_TYPE_CAL_BASE_SHELL_VIEW)
33 
34 static void
35 cal_shell_view_add_action_button (GtkBox *box,
36                                   GtkAction *action)
37 {
38 	GtkWidget *button, *icon;
39 
40 	button = gtk_button_new ();
41 	icon = gtk_action_create_icon (action, GTK_ICON_SIZE_MENU);
42 	gtk_image_set_pixel_size (GTK_IMAGE (icon), 16);
43 	gtk_button_set_image (GTK_BUTTON (button), icon);
44 	gtk_box_pack_start (box, button, FALSE, FALSE, 0);
45 	gtk_widget_show (button);
46 
47 	e_binding_bind_property (
48 		action, "visible",
49 		button, "visible",
50 		G_BINDING_SYNC_CREATE);
51 
52 	e_binding_bind_property (
53 		action, "sensitive",
54 		button, "sensitive",
55 		G_BINDING_SYNC_CREATE);
56 
57 	e_binding_bind_property (
58 		action, "tooltip",
59 		button, "tooltip-text",
60 		G_BINDING_SYNC_CREATE);
61 
62 	g_signal_connect_swapped (
63 		button, "clicked",
64 		G_CALLBACK (gtk_action_activate), action);
65 }
66 
67 static void
cal_shell_view_prepare_for_quit_cb(EShell * shell,EActivity * activity,ECalShellView * cal_shell_view)68 cal_shell_view_prepare_for_quit_cb (EShell *shell,
69                                     EActivity *activity,
70                                     ECalShellView *cal_shell_view)
71 {
72 	g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
73 
74 	/* Stop running searches, if any; the activity tight
75 	 * on the search prevents application from quitting. */
76 	e_cal_shell_view_search_stop (cal_shell_view);
77 }
78 
79 static void
cal_shell_view_execute_search(EShellView * shell_view)80 cal_shell_view_execute_search (EShellView *shell_view)
81 {
82 	ECalShellContent *cal_shell_content;
83 	ECalBaseShellSidebar *cal_shell_sidebar;
84 	EShellWindow *shell_window;
85 	EShellContent *shell_content;
86 	EShellSidebar *shell_sidebar;
87 	EShellSearchbar *searchbar;
88 	EActionComboBox *combo_box;
89 	ECalendar *calendar;
90 	ECalDataModel *data_model;
91 	GtkRadioAction *action;
92 	ICalTimezone *timezone;
93 	ICalTime *current_time;
94 	time_t start_range;
95 	time_t end_range;
96 	time_t now_time;
97 	gboolean range_search;
98 	gchar *query;
99 	gchar *temp;
100 	gint value;
101 
102 	e_cal_shell_view_search_stop (E_CAL_SHELL_VIEW (shell_view));
103 
104 	shell_window = e_shell_view_get_shell_window (shell_view);
105 	shell_content = e_shell_view_get_shell_content (shell_view);
106 	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
107 
108 	cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
109 	cal_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar);
110 
111 	searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
112 
113 	data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
114 	timezone = e_cal_data_model_get_timezone (data_model);
115 	current_time = i_cal_time_new_current_with_zone (timezone);
116 	now_time = time_day_begin (i_cal_time_as_timet (current_time));
117 	g_clear_object (&current_time);
118 
119 	action = GTK_RADIO_ACTION (ACTION (CALENDAR_SEARCH_ANY_FIELD_CONTAINS));
120 	value = gtk_radio_action_get_current_value (action);
121 
122 	if (value == CALENDAR_SEARCH_ADVANCED) {
123 		query = e_shell_view_get_search_query (shell_view);
124 
125 		if (!query)
126 			query = g_strdup ("");
127 	} else {
128 		const gchar *format;
129 		const gchar *text;
130 		GString *string;
131 
132 		text = e_shell_searchbar_get_search_text (searchbar);
133 
134 		if (text == NULL || *text == '\0') {
135 			text = "";
136 			value = CALENDAR_SEARCH_SUMMARY_CONTAINS;
137 		}
138 
139 		switch (value) {
140 			default:
141 				text = "";
142 				/* fall through */
143 
144 			case CALENDAR_SEARCH_SUMMARY_CONTAINS:
145 				format = "(contains? \"summary\" %s)";
146 				break;
147 
148 			case CALENDAR_SEARCH_DESCRIPTION_CONTAINS:
149 				format = "(contains? \"description\" %s)";
150 				break;
151 
152 			case CALENDAR_SEARCH_ANY_FIELD_CONTAINS:
153 				format = "(contains? \"any\" %s)";
154 				break;
155 		}
156 
157 		/* Build the query. */
158 		string = g_string_new ("");
159 		e_sexp_encode_string (string, text);
160 		query = g_strdup_printf (format, string->str);
161 		g_string_free (string, TRUE);
162 	}
163 
164 	range_search = FALSE;
165 	start_range = end_range = 0;
166 
167 	/* Apply selected filter. */
168 	combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
169 	value = e_action_combo_box_get_current_value (combo_box);
170 	switch (value) {
171 		case CALENDAR_FILTER_ANY_CATEGORY:
172 			break;
173 
174 		case CALENDAR_FILTER_UNMATCHED:
175 			temp = g_strdup_printf (
176 				"(and (has-categories? #f) %s)", query);
177 			g_free (query);
178 			query = temp;
179 			break;
180 
181 		case CALENDAR_FILTER_ACTIVE_APPOINTMENTS:
182 			/* Show a year's worth of appointments. */
183 			start_range = now_time;
184 			end_range = time_day_end (time_add_day (start_range, 365));
185 			range_search = TRUE;
186 			break;
187 
188 		case CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS:
189 			start_range = now_time;
190 			end_range = time_day_end (time_add_day (start_range, 7));
191 			range_search = TRUE;
192 			break;
193 
194 		case CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES:
195 			temp = g_strdup_printf (
196 				"(and %s (< (occurrences-count?) 5))", query);
197 			g_free (query);
198 			query = temp;
199 			break;
200 
201 		default:
202 		{
203 			GList *categories;
204 			const gchar *category_name;
205 
206 			categories = e_util_dup_searchable_categories ();
207 			category_name = g_list_nth_data (categories, value);
208 
209 			temp = g_strdup_printf (
210 				"(and (has-categories? \"%s\") %s)",
211 				category_name, query);
212 			g_free (query);
213 			query = temp;
214 
215 			g_list_free_full (categories, g_free);
216 			break;
217 		}
218 	}
219 
220 	calendar = e_cal_base_shell_sidebar_get_date_navigator (cal_shell_sidebar);
221 
222 	if (range_search) {
223 		/* Switch to list view and hide the date navigator. */
224 		action = GTK_RADIO_ACTION (ACTION (CALENDAR_VIEW_LIST));
225 		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
226 		gtk_widget_hide (GTK_WIDGET (calendar));
227 	} else {
228 		/* Ensure the date navigator is visible. */
229 		gtk_widget_show (GTK_WIDGET (calendar));
230 		e_cal_shell_content_get_current_range (cal_shell_content, &start_range, &end_range);
231 		end_range = time_day_end (end_range) - 1;
232 	}
233 
234 	/* Submit the query. */
235 	e_cal_shell_content_update_filters (cal_shell_content, query, start_range, end_range);
236 
237 	g_free (query);
238 
239 	/* Update actions so Find Prev/Next/Stop
240 	 * buttons will be sensitive as expected. */
241 	e_shell_view_update_actions (shell_view);
242 }
243 
244 static void
cal_shell_view_update_actions(EShellView * shell_view)245 cal_shell_view_update_actions (EShellView *shell_view)
246 {
247 	ECalShellViewPrivate *priv;
248 	ECalShellContent *cal_shell_content;
249 	EShellContent *shell_content;
250 	EShellSidebar *shell_sidebar;
251 	EShellWindow *shell_window;
252 	EShell *shell;
253 	ESource *source;
254 	ESourceRegistry *registry;
255 	ECalendarView *cal_view;
256 	EMemoTable *memo_table;
257 	ETaskTable *task_table;
258 	ECalDataModel *data_model;
259 	GtkAction *action;
260 	gchar *data_filter;
261 	gboolean is_searching;
262 	gboolean is_list_view;
263 	gboolean sensitive;
264 	guint32 state;
265 
266 	/* Be descriptive. */
267 	gboolean any_events_selected;
268 	gboolean has_mail_identity = FALSE;
269 	gboolean has_primary_source;
270 	gboolean primary_source_is_writable;
271 	gboolean primary_source_is_removable;
272 	gboolean primary_source_is_remote_deletable;
273 	gboolean primary_source_in_collection;
274 	gboolean multiple_events_selected;
275 	gboolean selection_is_editable;
276 	gboolean selection_is_instance;
277 	gboolean selection_is_meeting;
278 	gboolean selection_is_recurring;
279 	gboolean selection_is_attendee;
280 	gboolean selection_can_delegate;
281 	gboolean single_event_selected;
282 	gboolean refresh_supported;
283 	gboolean all_sources_selected;
284 	gboolean clicked_source_is_primary;
285 	gboolean clicked_source_is_collection;
286 	gboolean this_and_future_supported;
287 
288 	/* Chain up to parent's update_actions() method. */
289 	E_SHELL_VIEW_CLASS (e_cal_shell_view_parent_class)->
290 		update_actions (shell_view);
291 
292 	priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
293 
294 	shell_window = e_shell_view_get_shell_window (shell_view);
295 	shell = e_shell_window_get_shell (shell_window);
296 
297 	registry = e_shell_get_registry (shell);
298 	source = e_source_registry_ref_default_mail_identity (registry);
299 	has_mail_identity = (source != NULL);
300 	if (source != NULL) {
301 		has_mail_identity = TRUE;
302 		g_object_unref (source);
303 	}
304 
305 	cal_shell_content = priv->cal_shell_content;
306 	cal_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
307 	memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
308 	task_table = e_cal_shell_content_get_task_table (cal_shell_content);
309 	is_list_view = E_IS_CAL_LIST_VIEW (cal_view);
310 	if (is_list_view)
311 		data_model = e_cal_shell_content_get_list_view_data_model (cal_shell_content);
312 	else
313 		data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
314 	data_filter = e_cal_data_model_dup_filter (data_model);
315 	is_searching = data_filter && *data_filter &&
316 		g_strcmp0 (data_filter, "#t") != 0 &&
317 		g_strcmp0 (data_filter, "(contains? \"summary\"  \"\")") != 0;
318 	g_free (data_filter);
319 
320 	shell_content = e_shell_view_get_shell_content (shell_view);
321 	state = e_shell_content_check_state (shell_content);
322 
323 	single_event_selected =
324 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE);
325 	multiple_events_selected =
326 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE);
327 	selection_is_editable =
328 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE);
329 	selection_is_instance =
330 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_INSTANCE);
331 	selection_is_meeting =
332 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_MEETING);
333 	selection_is_attendee =
334 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_ATTENDEE);
335 	selection_is_recurring =
336 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_RECURRING);
337 	selection_can_delegate =
338 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_DELEGATE);
339 	this_and_future_supported =
340 		(state & E_CAL_BASE_SHELL_CONTENT_SELECTION_THIS_AND_FUTURE_SUPPORTED);
341 
342 	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
343 	state = e_shell_sidebar_check_state (shell_sidebar);
344 
345 	has_primary_source =
346 		(state & E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
347 	primary_source_is_writable =
348 		(state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
349 	primary_source_is_removable =
350 		(state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
351 	primary_source_is_remote_deletable =
352 		(state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
353 	primary_source_in_collection =
354 		(state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
355 	refresh_supported =
356 		(state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
357 	all_sources_selected =
358 		(state & E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED) != 0;
359 	clicked_source_is_primary =
360 		(state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY) != 0;
361 	clicked_source_is_collection =
362 		(state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION) != 0;
363 
364 	any_events_selected = (single_event_selected || multiple_events_selected);
365 
366 	action = ACTION (CALENDAR_SELECT_ALL);
367 	sensitive = clicked_source_is_primary && !all_sources_selected;
368 	gtk_action_set_sensitive (action, sensitive);
369 
370 	action = ACTION (CALENDAR_SELECT_ONE);
371 	sensitive = clicked_source_is_primary;
372 	gtk_action_set_sensitive (action, sensitive);
373 
374 	action = ACTION (CALENDAR_COPY);
375 	sensitive = has_primary_source;
376 	gtk_action_set_sensitive (action, sensitive);
377 
378 	action = ACTION (CALENDAR_DELETE);
379 	sensitive =
380 		primary_source_is_removable ||
381 		primary_source_is_remote_deletable;
382 	gtk_action_set_sensitive (action, sensitive);
383 
384 	action = ACTION (CALENDAR_PRINT);
385 	sensitive = TRUE;
386 	gtk_action_set_sensitive (action, sensitive);
387 
388 	action = ACTION (CALENDAR_PRINT_PREVIEW);
389 	sensitive = TRUE;
390 	gtk_action_set_sensitive (action, sensitive);
391 
392 	action = ACTION (CALENDAR_PROPERTIES);
393 	sensitive = clicked_source_is_primary && primary_source_is_writable;
394 	gtk_action_set_sensitive (action, sensitive);
395 
396 	action = ACTION (CALENDAR_REFRESH);
397 	sensitive = clicked_source_is_primary && refresh_supported;
398 	gtk_action_set_sensitive (action, sensitive);
399 
400 	action = ACTION (CALENDAR_REFRESH_BACKEND);
401 	sensitive = clicked_source_is_collection;
402 	gtk_action_set_sensitive (action, sensitive);
403 
404 	action = ACTION (CALENDAR_RENAME);
405 	sensitive = clicked_source_is_primary &&
406 		primary_source_is_writable &&
407 		!primary_source_in_collection;
408 	gtk_action_set_sensitive (action, sensitive);
409 
410 	action = ACTION (CALENDAR_SEARCH_PREV);
411 	gtk_action_set_sensitive (action, is_searching && !is_list_view);
412 
413 	action = ACTION (CALENDAR_SEARCH_NEXT);
414 	gtk_action_set_sensitive (action, is_searching && !is_list_view);
415 
416 	action = ACTION (CALENDAR_SEARCH_STOP);
417 	sensitive = is_searching && priv->searching_activity != NULL;
418 	gtk_action_set_sensitive (action, sensitive);
419 
420 	action = ACTION (EVENT_DELEGATE);
421 	sensitive =
422 		single_event_selected &&
423 		selection_is_editable &&
424 		selection_can_delegate &&
425 		selection_is_meeting;
426 	gtk_action_set_sensitive (action, sensitive);
427 
428 	action = ACTION (EVENT_DELETE);
429 	sensitive =
430 		any_events_selected &&
431 		selection_is_editable &&
432 		!selection_is_recurring;
433 	gtk_action_set_sensitive (action, sensitive);
434 
435 	action = ACTION (EVENT_DELETE_OCCURRENCE);
436 	sensitive =
437 		any_events_selected &&
438 		selection_is_editable &&
439 		selection_is_recurring;
440 	gtk_action_set_sensitive (action, sensitive);
441 
442 	action = ACTION (EVENT_DELETE_OCCURRENCE_THIS_AND_FUTURE);
443 	sensitive =
444 		single_event_selected &&
445 		selection_is_editable &&
446 		selection_is_recurring &&
447 		this_and_future_supported;
448 	gtk_action_set_sensitive (action, sensitive);
449 
450 	action = ACTION (EVENT_DELETE_OCCURRENCE_ALL);
451 	sensitive =
452 		any_events_selected &&
453 		selection_is_editable &&
454 		selection_is_recurring;
455 	gtk_action_set_sensitive (action, sensitive);
456 
457 	action = ACTION (EVENT_FORWARD);
458 	sensitive = single_event_selected;
459 	gtk_action_set_sensitive (action, sensitive);
460 
461 	action = ACTION (EVENT_OCCURRENCE_MOVABLE);
462 	sensitive =
463 		single_event_selected &&
464 		selection_is_editable &&
465 		selection_is_recurring &&
466 		selection_is_instance;
467 	gtk_action_set_sensitive (action, sensitive);
468 
469 	action = ACTION (EVENT_OPEN);
470 	sensitive = single_event_selected;
471 	gtk_action_set_sensitive (action, sensitive);
472 
473 	action = ACTION (EVENT_EDIT_AS_NEW);
474 	sensitive = single_event_selected &&
475 		!selection_is_instance;
476 	gtk_action_set_sensitive (action, sensitive);
477 
478 	action = ACTION (EVENT_PRINT);
479 	sensitive = single_event_selected;
480 	gtk_action_set_sensitive (action, sensitive);
481 
482 	action = ACTION (EVENT_SAVE_AS);
483 	sensitive = single_event_selected;
484 	gtk_action_set_sensitive (action, sensitive);
485 
486 	action = ACTION (EVENT_SCHEDULE);
487 	sensitive =
488 		single_event_selected &&
489 		selection_is_editable &&
490 		!selection_is_meeting;
491 	gtk_action_set_sensitive (action, sensitive);
492 
493 	action = ACTION (EVENT_SCHEDULE_APPOINTMENT);
494 	sensitive =
495 		single_event_selected &&
496 		selection_is_editable &&
497 		selection_is_meeting;
498 	gtk_action_set_sensitive (action, sensitive);
499 
500 	action = ACTION (EVENT_REPLY);
501 	sensitive = single_event_selected && selection_is_meeting;
502 	gtk_action_set_sensitive (action, sensitive);
503 
504 	action = ACTION (EVENT_REPLY_ALL);
505 	sensitive = single_event_selected && selection_is_meeting;
506 	gtk_action_set_sensitive (action, sensitive);
507 
508 	action = ACTION (EVENT_POPUP_MEETING_NEW);
509 	gtk_action_set_visible (action, has_mail_identity);
510 
511 	action = ACTION (EVENT_POPUP_RSVP_SUBMENU);
512 	gtk_action_set_visible (action, selection_is_attendee);
513 
514 	sensitive = selection_is_instance || selection_is_recurring;
515 	gtk_action_set_visible (ACTION (EVENT_POPUP_RSVP_ACCEPT_1), sensitive);
516 	gtk_action_set_visible (ACTION (EVENT_POPUP_RSVP_DECLINE_1), sensitive);
517 	gtk_action_set_visible (ACTION (EVENT_POPUP_RSVP_TENTATIVE_1), sensitive);
518 
519 	gtk_action_set_sensitive (ACTION (CALENDAR_GO_BACK), !is_list_view);
520 	gtk_action_set_sensitive (ACTION (CALENDAR_GO_FORWARD), !is_list_view);
521 	gtk_action_set_sensitive (ACTION (CALENDAR_GO_TODAY), !is_list_view);
522 	gtk_action_set_sensitive (ACTION (CALENDAR_JUMP_TO), !is_list_view);
523 
524 	if ((cal_view && e_calendar_view_is_editing (cal_view)) ||
525 	    e_table_is_editing (E_TABLE (memo_table)) ||
526 	    e_table_is_editing (E_TABLE (task_table))) {
527 		EFocusTracker *focus_tracker;
528 
529 		/* disable all clipboard actions, if any of the views is in editing mode */
530 		focus_tracker = e_shell_window_get_focus_tracker (shell_window);
531 
532 		action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
533 		if (action)
534 			gtk_action_set_sensitive (action, FALSE);
535 
536 		action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
537 		if (action)
538 			gtk_action_set_sensitive (action, FALSE);
539 
540 		action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
541 		if (action)
542 			gtk_action_set_sensitive (action, FALSE);
543 
544 		action = e_focus_tracker_get_delete_selection_action (focus_tracker);
545 		if (action)
546 			gtk_action_set_sensitive (action, FALSE);
547 	}
548 }
549 
550 static void
cal_shell_view_dispose(GObject * object)551 cal_shell_view_dispose (GObject *object)
552 {
553 	e_cal_shell_view_private_dispose (E_CAL_SHELL_VIEW (object));
554 
555 	/* Chain up to parent's dispose() method. */
556 	G_OBJECT_CLASS (e_cal_shell_view_parent_class)->dispose (object);
557 }
558 
559 static void
cal_shell_view_finalize(GObject * object)560 cal_shell_view_finalize (GObject *object)
561 {
562 	e_cal_shell_view_private_finalize (E_CAL_SHELL_VIEW (object));
563 
564 	/* Chain up to parent's finalize() method. */
565 	G_OBJECT_CLASS (e_cal_shell_view_parent_class)->finalize (object);
566 }
567 
568 static void
cal_shell_view_constructed(GObject * object)569 cal_shell_view_constructed (GObject *object)
570 {
571 	EShell *shell;
572 	EShellView *shell_view;
573 	EShellWindow *shell_window;
574 	EShellSearchbar *searchbar;
575 	ECalShellView *cal_shell_view;
576 	ECalShellContent *cal_shell_content;
577 	GtkWidget *container;
578 	GtkWidget *widget;
579 	gulong handler_id;
580 
581 	/* Chain up to parent's constructed() method. */
582 	G_OBJECT_CLASS (e_cal_shell_view_parent_class)->constructed (object);
583 
584 	cal_shell_view = E_CAL_SHELL_VIEW (object);
585 	e_cal_shell_view_private_constructed (cal_shell_view);
586 
587 	shell_view = E_SHELL_VIEW (cal_shell_view);
588 	shell_window = e_shell_view_get_shell_window (shell_view);
589 	shell = e_shell_window_get_shell (shell_window);
590 
591 	cal_shell_content = cal_shell_view->priv->cal_shell_content;
592 	searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
593 	container = e_shell_searchbar_get_search_box (searchbar);
594 
595 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
596 	gtk_style_context_add_class (
597 		gtk_widget_get_style_context (widget), "linked");
598 	cal_shell_view_add_action_button (
599 		GTK_BOX (widget), ACTION (CALENDAR_SEARCH_PREV));
600 	cal_shell_view_add_action_button (
601 		GTK_BOX (widget), ACTION (CALENDAR_SEARCH_NEXT));
602 	cal_shell_view_add_action_button (
603 		GTK_BOX (widget), ACTION (CALENDAR_SEARCH_STOP));
604 	gtk_container_add (GTK_CONTAINER (container), widget);
605 	gtk_widget_show (widget);
606 
607 	handler_id = g_signal_connect (
608 		shell, "prepare-for-quit",
609 		G_CALLBACK (cal_shell_view_prepare_for_quit_cb),
610 		cal_shell_view);
611 
612 	cal_shell_view->priv->shell = g_object_ref (shell);
613 	cal_shell_view->priv->prepare_for_quit_handler_id = handler_id;
614 }
615 
616 static void
e_cal_shell_view_class_init(ECalShellViewClass * class)617 e_cal_shell_view_class_init (ECalShellViewClass *class)
618 {
619 	GObjectClass *object_class;
620 	EShellViewClass *shell_view_class;
621 	ECalBaseShellViewClass *cal_base_shell_view_class;
622 
623 	g_type_class_add_private (class, sizeof (ECalShellViewPrivate));
624 
625 	object_class = G_OBJECT_CLASS (class);
626 	object_class->dispose = cal_shell_view_dispose;
627 	object_class->finalize = cal_shell_view_finalize;
628 	object_class->constructed = cal_shell_view_constructed;
629 
630 	shell_view_class = E_SHELL_VIEW_CLASS (class);
631 	shell_view_class->label = _("Calendar");
632 	shell_view_class->icon_name = "x-office-calendar";
633 	shell_view_class->ui_definition = "evolution-calendars.ui";
634 	shell_view_class->ui_manager_id = "org.gnome.evolution.calendars";
635 	shell_view_class->search_options = "/calendar-search-options";
636 	shell_view_class->search_rules = "caltypes.xml";
637 	shell_view_class->new_shell_content = e_cal_shell_content_new;
638 	shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new;
639 	shell_view_class->execute_search = cal_shell_view_execute_search;
640 	shell_view_class->update_actions = cal_shell_view_update_actions;
641 
642 	cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class);
643 	cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
644 
645 	/* Ensure the GalView types we need are registered. */
646 	g_type_ensure (GAL_TYPE_VIEW_CALENDAR_DAY);
647 	g_type_ensure (GAL_TYPE_VIEW_CALENDAR_WORK_WEEK);
648 	g_type_ensure (GAL_TYPE_VIEW_CALENDAR_WEEK);
649 	g_type_ensure (GAL_TYPE_VIEW_CALENDAR_MONTH);
650 	g_type_ensure (GAL_TYPE_VIEW_ETABLE);
651 
652 	e_calendar_a11y_init ();
653 }
654 
655 static void
e_cal_shell_view_class_finalize(ECalShellViewClass * class)656 e_cal_shell_view_class_finalize (ECalShellViewClass *class)
657 {
658 }
659 
660 static void
e_cal_shell_view_init(ECalShellView * cal_shell_view)661 e_cal_shell_view_init (ECalShellView *cal_shell_view)
662 {
663 	cal_shell_view->priv = E_CAL_SHELL_VIEW_GET_PRIVATE (cal_shell_view);
664 
665 	e_cal_shell_view_private_init (cal_shell_view);
666 }
667 
668 void
e_cal_shell_view_type_register(GTypeModule * type_module)669 e_cal_shell_view_type_register (GTypeModule *type_module)
670 {
671 	/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
672 	 *     function, so we have to wrap it with a public function in
673 	 *     order to register types from a separate compilation unit. */
674 	e_cal_shell_view_register_type (type_module);
675 }
676