1 /*
2  * evolution-cal-config-local.c
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include "evolution-config.h"
19 
20 #include <glib/gi18n-lib.h>
21 
22 #include <libebackend/libebackend.h>
23 #include <libedataserver/libedataserver.h>
24 
25 #include "e-util/e-util.h"
26 #include "calendar/gui/itip-utils.h"
27 
28 typedef ESourceConfigBackend ECalConfigLocal;
29 typedef ESourceConfigBackendClass ECalConfigLocalClass;
30 
31 typedef struct _Context Context;
32 
33 struct _Context {
34 	GtkWidget *custom_file_checkbox;
35 	GtkWidget *custom_file_chooser;
36 	GtkWidget *writable_checkbox;
37 };
38 
39 /* Module Entry Points */
40 void e_module_load (GTypeModule *type_module);
41 void e_module_unload (GTypeModule *type_module);
42 
43 /* Forward Declarations */
44 GType e_cal_config_local_get_type (void);
45 
G_DEFINE_DYNAMIC_TYPE(ECalConfigLocal,e_cal_config_local,E_TYPE_SOURCE_CONFIG_BACKEND)46 G_DEFINE_DYNAMIC_TYPE (
47 	ECalConfigLocal,
48 	e_cal_config_local,
49 	E_TYPE_SOURCE_CONFIG_BACKEND)
50 
51 static void
52 cal_config_local_fill_addresses (ESourceRegistry *registry,
53 				 GtkComboBoxText *combo_box)
54 {
55 	gchar **address_strings;
56 	gint ii;
57 
58 	address_strings = itip_get_user_identities (registry);
59 
60 	for (ii = 0; address_strings && address_strings[ii]; ii++) {
61 		gtk_combo_box_text_append_text (combo_box, address_strings[ii]);
62 	}
63 
64 	g_strfreev (address_strings);
65 }
66 
67 static void
cal_config_local_context_free(Context * context)68 cal_config_local_context_free (Context *context)
69 {
70 	g_object_unref (context->custom_file_checkbox);
71 	g_object_unref (context->custom_file_chooser);
72 	g_object_unref (context->writable_checkbox);
73 
74 	g_slice_free (Context, context);
75 }
76 
77 static gboolean
cal_config_local_active_to_custom_file(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)78 cal_config_local_active_to_custom_file (GBinding *binding,
79                                         const GValue *source_value,
80                                         GValue *target_value,
81                                         gpointer user_data)
82 {
83 	Context *context = user_data;
84 	GtkFileChooser *file_chooser;
85 	GFile *file = NULL;
86 
87 	file_chooser = GTK_FILE_CHOOSER (context->custom_file_chooser);
88 
89 	if (g_value_get_boolean (source_value))
90 		file = gtk_file_chooser_get_file (file_chooser);
91 
92 	g_value_take_object (target_value, file);
93 
94 	return TRUE;
95 }
96 
97 static gboolean
cal_config_local_custom_file_to_active(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)98 cal_config_local_custom_file_to_active (GBinding *binding,
99                                         const GValue *source_value,
100                                         GValue *target_value,
101                                         gpointer user_data)
102 {
103 	Context *context = user_data;
104 	GtkFileChooser *file_chooser;
105 	GFile *file;
106 	gboolean success;
107 
108 	file_chooser = GTK_FILE_CHOOSER (context->custom_file_chooser);
109 
110 	file = g_value_get_object (source_value);
111 
112 	if (file == NULL) {
113 		g_value_set_boolean (target_value, FALSE);
114 		return TRUE;
115 	}
116 
117 	success = gtk_file_chooser_set_file (file_chooser, file, NULL);
118 	g_value_set_boolean (target_value, success);
119 
120 	return success;
121 }
122 
123 static void
cal_config_local_file_set_cb(GtkFileChooserButton * button,GtkWidget * custom_file_checkbox)124 cal_config_local_file_set_cb (GtkFileChooserButton *button,
125                               GtkWidget *custom_file_checkbox)
126 {
127 	/* This will update ESourceLocal:custom-file. */
128 	g_object_notify (G_OBJECT (custom_file_checkbox), "active");
129 }
130 
131 static void
cal_config_local_insert_widgets(ESourceConfigBackend * backend,ESource * scratch_source)132 cal_config_local_insert_widgets (ESourceConfigBackend *backend,
133                                  ESource *scratch_source)
134 {
135 	ESourceConfig *config;
136 	ESource *builtin_source;
137 	ESourceRegistry *registry;
138 	ESourceExtension *extension;
139 	GtkFileFilter *filter;
140 	GtkWidget *container;
141 	GtkWidget *widget;
142 	Context *context;
143 	gboolean source_is_builtin = FALSE;
144 	const gchar *extension_name;
145 	const gchar *uid;
146 	gchar *markup;
147 
148 	uid = e_source_get_uid (scratch_source);
149 	config = e_source_config_backend_get_config (backend);
150 	registry = e_source_config_get_registry (config);
151 
152 	/* The built-in sources can't use a custom file. */
153 
154 	builtin_source = e_source_registry_ref_builtin_calendar (registry);
155 	source_is_builtin |= e_source_equal (scratch_source, builtin_source);
156 	g_object_unref (builtin_source);
157 
158 	builtin_source = e_source_registry_ref_builtin_memo_list (registry);
159 	source_is_builtin |= e_source_equal (scratch_source, builtin_source);
160 	g_object_unref (builtin_source);
161 
162 	builtin_source = e_source_registry_ref_builtin_task_list (registry);
163 	source_is_builtin |= e_source_equal (scratch_source, builtin_source);
164 	g_object_unref (builtin_source);
165 
166 	extension_name = E_SOURCE_EXTENSION_LOCAL_BACKEND;
167 	extension = e_source_get_extension (scratch_source, extension_name);
168 
169 	if (!source_is_builtin) {
170 		context = g_slice_new (Context);
171 
172 		g_object_set_data_full (
173 			G_OBJECT (backend), uid, context,
174 			(GDestroyNotify) cal_config_local_context_free);
175 
176 		widget = gtk_check_button_new_with_label (
177 			_("Use an existing iCalendar (ics) file"));
178 		e_source_config_insert_widget (
179 			config, scratch_source, NULL, widget);
180 		context->custom_file_checkbox = g_object_ref (widget);
181 		gtk_widget_show (widget);
182 
183 		g_signal_connect_swapped (
184 			widget, "toggled",
185 			G_CALLBACK (e_source_config_resize_window), config);
186 
187 		container = e_source_config_get_page (config, scratch_source);
188 
189 		/* Put some extra padding above and below the header. */
190 		widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
191 		gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 12, 6, 0, 0);
192 		gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
193 		gtk_widget_show (widget);
194 
195 		e_binding_bind_property (
196 			context->custom_file_checkbox, "active",
197 			widget, "visible",
198 			G_BINDING_SYNC_CREATE);
199 
200 		container = widget;
201 
202 		markup = g_markup_printf_escaped ("<b>%s</b>", _("iCalendar File"));
203 		widget = gtk_label_new (markup);
204 		gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
205 		gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
206 		gtk_container_add (GTK_CONTAINER (container), widget);
207 		gtk_widget_show (widget);
208 		g_free (markup);
209 
210 		filter = gtk_file_filter_new ();
211 		gtk_file_filter_add_mime_type (filter, "text/calendar");
212 
213 		widget = gtk_file_chooser_button_new (
214 			_("Choose an iCalendar file"), GTK_FILE_CHOOSER_ACTION_OPEN);
215 		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter);
216 		e_source_config_insert_widget (
217 			config, scratch_source, _("File:"), widget);
218 		context->custom_file_chooser = g_object_ref (widget);
219 		gtk_widget_show (widget);
220 
221 		g_signal_connect (
222 			widget, "file-set",
223 			G_CALLBACK (cal_config_local_file_set_cb),
224 			context->custom_file_checkbox);
225 
226 		e_binding_bind_property (
227 			context->custom_file_checkbox, "active",
228 			widget, "visible",
229 			G_BINDING_SYNC_CREATE);
230 
231 		widget = gtk_check_button_new_with_label (
232 			_("Allow Evolution to update the file"));
233 		e_source_config_insert_widget (
234 			config, scratch_source, NULL, widget);
235 		context->writable_checkbox = g_object_ref (widget);
236 		gtk_widget_show (widget);
237 
238 		e_binding_bind_property (
239 			context->custom_file_checkbox, "active",
240 			widget, "visible",
241 			G_BINDING_SYNC_CREATE);
242 
243 		e_binding_bind_property_full (
244 			extension, "custom-file",
245 			context->custom_file_checkbox, "active",
246 			G_BINDING_BIDIRECTIONAL |
247 			G_BINDING_SYNC_CREATE,
248 			cal_config_local_custom_file_to_active,
249 			cal_config_local_active_to_custom_file,
250 			context, (GDestroyNotify) NULL);
251 
252 		e_binding_bind_property (
253 			extension, "writable",
254 			context->writable_checkbox, "active",
255 			G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
256 	}
257 
258 	widget = e_ellipsized_combo_box_text_new (TRUE);
259 	cal_config_local_fill_addresses (registry, GTK_COMBO_BOX_TEXT (widget));
260 	e_source_config_insert_widget (config, scratch_source, _("Email:"), widget);
261 	gtk_widget_show (widget);
262 
263 	e_binding_bind_object_text_property (
264 		extension, "email-address",
265 		gtk_bin_get_child (GTK_BIN (widget)), "text",
266 		G_BINDING_BIDIRECTIONAL |
267 		G_BINDING_SYNC_CREATE);
268 }
269 
270 static gboolean
cal_config_local_check_complete(ESourceConfigBackend * backend,ESource * scratch_source)271 cal_config_local_check_complete (ESourceConfigBackend *backend,
272                                  ESource *scratch_source)
273 {
274 	ESourceLocal *extension;
275 	GtkToggleButton *toggle_button;
276 	Context *context;
277 	GFile *file;
278 	const gchar *extension_name;
279 	const gchar *uid;
280 	gboolean active;
281 
282 	uid = e_source_get_uid (scratch_source);
283 	context = g_object_get_data (G_OBJECT (backend), uid);
284 
285 	/* This function might get called before we install a
286 	 * context for this ESource, in which case just return. */
287 	if (context == NULL)
288 		return FALSE;
289 
290 	extension_name = E_SOURCE_EXTENSION_LOCAL_BACKEND;
291 	extension = e_source_get_extension (scratch_source, extension_name);
292 
293 	file = e_source_local_get_custom_file (extension);
294 
295 	toggle_button = GTK_TOGGLE_BUTTON (context->custom_file_checkbox);
296 	active = gtk_toggle_button_get_active (toggle_button);
297 
298 	/* If toggle button is active we need a valid file. */
299 	return !active || (file != NULL);
300 }
301 
302 static void
e_cal_config_local_class_init(ESourceConfigBackendClass * class)303 e_cal_config_local_class_init (ESourceConfigBackendClass *class)
304 {
305 	EExtensionClass *extension_class;
306 
307 	extension_class = E_EXTENSION_CLASS (class);
308 	extension_class->extensible_type = E_TYPE_CAL_SOURCE_CONFIG;
309 
310 	class->parent_uid = "local-stub";
311 	class->backend_name = "local";
312 	class->insert_widgets = cal_config_local_insert_widgets;
313 	class->check_complete = cal_config_local_check_complete;
314 }
315 
316 static void
e_cal_config_local_class_finalize(ESourceConfigBackendClass * class)317 e_cal_config_local_class_finalize (ESourceConfigBackendClass *class)
318 {
319 }
320 
321 static void
e_cal_config_local_init(ESourceConfigBackend * backend)322 e_cal_config_local_init (ESourceConfigBackend *backend)
323 {
324 }
325 
326 G_MODULE_EXPORT void
e_module_load(GTypeModule * type_module)327 e_module_load (GTypeModule *type_module)
328 {
329 	e_cal_config_local_register_type (type_module);
330 }
331 
332 G_MODULE_EXPORT void
e_module_unload(GTypeModule * type_module)333 e_module_unload (GTypeModule *type_module)
334 {
335 }
336