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