1 /*
2  * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU 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 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 <errno.h>
21 #include <glib/gi18n-lib.h>
22 
23 #include <libedataserver/libedataserver.h>
24 #include <libedataserverui/libedataserverui.h>
25 #include <e-util/e-util.h>
26 
27 #include "calendar-config.h"
28 #include "comp-util.h"
29 #include "e-cal-model.h"
30 #include "e-timezone-entry.h"
31 
32 #include "e-comp-editor-property-part.h"
33 #include "e-comp-editor-property-parts.h"
34 
35 /* ************************************************************************* */
36 
37 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_SUMMARY \
38 	(e_comp_editor_property_part_summary_get_type ())
39 #define E_COMP_EDITOR_PROPERTY_PART_SUMMARY(obj) \
40 	(G_TYPE_CHECK_INSTANCE_CAST \
41 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_SUMMARY, ECompEditorPropertyPartSummary))
42 #define E_IS_COMP_EDITOR_PROPERTY_PART_SUMMARY(obj) \
43 	(G_TYPE_CHECK_INSTANCE_TYPE \
44 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_SUMMARY))
45 
46 typedef struct _ECompEditorPropertyPartSummary ECompEditorPropertyPartSummary;
47 typedef struct _ECompEditorPropertyPartSummaryClass ECompEditorPropertyPartSummaryClass;
48 
49 struct _ECompEditorPropertyPartSummary {
50 	ECompEditorPropertyPartString parent;
51 };
52 
53 struct _ECompEditorPropertyPartSummaryClass {
54 	ECompEditorPropertyPartStringClass parent_class;
55 };
56 
57 GType e_comp_editor_property_part_summary_get_type (void) G_GNUC_CONST;
58 
G_DEFINE_TYPE(ECompEditorPropertyPartSummary,e_comp_editor_property_part_summary,E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)59 G_DEFINE_TYPE (ECompEditorPropertyPartSummary, e_comp_editor_property_part_summary, E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)
60 
61 static void
62 ecepp_summary_insert_text_cb (GtkEditable *editable,
63 			      gchar *new_text,
64 			      gint new_text_length,
65 			      gpointer position,
66 			      gpointer user_data)
67 {
68 	e_cal_model_until_sanitize_text_value (new_text, new_text_length);
69 }
70 
71 static void
ecepp_summary_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)72 ecepp_summary_create_widgets (ECompEditorPropertyPart *property_part,
73 			      GtkWidget **out_label_widget,
74 			      GtkWidget **out_edit_widget)
75 {
76 	ECompEditorPropertyPartClass *part_class;
77 
78 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SUMMARY (property_part));
79 	g_return_if_fail (out_label_widget != NULL);
80 	g_return_if_fail (out_edit_widget != NULL);
81 
82 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_summary_parent_class);
83 	g_return_if_fail (part_class != NULL);
84 	g_return_if_fail (part_class->create_widgets != NULL);
85 
86 	*out_label_widget = NULL;
87 
88 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
89 	g_return_if_fail (*out_label_widget == NULL);
90 	g_return_if_fail (*out_edit_widget != NULL);
91 
92 	*out_label_widget = gtk_label_new_with_mnemonic (C_("ECompEditor", "_Summary:"));
93 	gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
94 
95 	g_object_set (G_OBJECT (*out_label_widget),
96 		"hexpand", FALSE,
97 		"halign", GTK_ALIGN_END,
98 		"vexpand", FALSE,
99 		"valign", GTK_ALIGN_CENTER,
100 		NULL);
101 
102 	gtk_widget_show (*out_label_widget);
103 
104 	if (GTK_IS_EDITABLE (*out_edit_widget)) {
105 		g_signal_connect (*out_edit_widget, "insert-text",
106 			G_CALLBACK (ecepp_summary_insert_text_cb), NULL);
107 	}
108 }
109 
110 static void
e_comp_editor_property_part_summary_init(ECompEditorPropertyPartSummary * part_summary)111 e_comp_editor_property_part_summary_init (ECompEditorPropertyPartSummary *part_summary)
112 {
113 }
114 
115 static void
e_comp_editor_property_part_summary_class_init(ECompEditorPropertyPartSummaryClass * klass)116 e_comp_editor_property_part_summary_class_init (ECompEditorPropertyPartSummaryClass *klass)
117 {
118 	ECompEditorPropertyPartStringClass *part_string_class;
119 	ECompEditorPropertyPartClass *part_class;
120 
121 	part_string_class = E_COMP_EDITOR_PROPERTY_PART_STRING_CLASS (klass);
122 	part_string_class->entry_type = E_TYPE_SPELL_ENTRY;
123 	part_string_class->prop_kind = I_CAL_SUMMARY_PROPERTY;
124 	part_string_class->i_cal_new_func = i_cal_property_new_summary;
125 	part_string_class->i_cal_set_func = i_cal_property_set_summary;
126 	part_string_class->i_cal_get_func = i_cal_property_get_summary;
127 
128 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
129 	part_class->create_widgets = ecepp_summary_create_widgets;
130 }
131 
132 ECompEditorPropertyPart *
e_comp_editor_property_part_summary_new(EFocusTracker * focus_tracker)133 e_comp_editor_property_part_summary_new (EFocusTracker *focus_tracker)
134 {
135 	ECompEditorPropertyPart *property_part;
136 
137 	property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_SUMMARY, NULL);
138 
139 	e_comp_editor_property_part_string_attach_focus_tracker (
140 		E_COMP_EDITOR_PROPERTY_PART_STRING (property_part), focus_tracker);
141 
142 	return property_part;
143 }
144 
145 /* ************************************************************************* */
146 
147 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_LOCATION \
148 	(e_comp_editor_property_part_location_get_type ())
149 #define E_COMP_EDITOR_PROPERTY_PART_LOCATION(obj) \
150 	(G_TYPE_CHECK_INSTANCE_CAST \
151 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_LOCATION, ECompEditorPropertyPartLocation))
152 #define E_IS_COMP_EDITOR_PROPERTY_PART_LOCATION(obj) \
153 	(G_TYPE_CHECK_INSTANCE_TYPE \
154 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_LOCATION))
155 
156 typedef struct _ECompEditorPropertyPartLocation ECompEditorPropertyPartLocation;
157 typedef struct _ECompEditorPropertyPartLocationClass ECompEditorPropertyPartLocationClass;
158 
159 struct _ECompEditorPropertyPartLocation {
160 	ECompEditorPropertyPartString parent;
161 };
162 
163 struct _ECompEditorPropertyPartLocationClass {
164 	ECompEditorPropertyPartStringClass parent_class;
165 };
166 
167 GType e_comp_editor_property_part_location_get_type (void) G_GNUC_CONST;
168 
G_DEFINE_TYPE(ECompEditorPropertyPartLocation,e_comp_editor_property_part_location,E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)169 G_DEFINE_TYPE (ECompEditorPropertyPartLocation, e_comp_editor_property_part_location, E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)
170 
171 static gchar *
172 ecepp_location_get_locations_filename (gboolean config_dir_only)
173 {
174 	return g_build_filename (e_get_user_config_dir (), "calendar", config_dir_only ? NULL : "locations", NULL);
175 }
176 
177 static void
ecepp_location_load_list(GtkEntry * entry)178 ecepp_location_load_list (GtkEntry *entry)
179 {
180 	GtkEntryCompletion *completion;
181 	GtkListStore *store;
182 	gchar *filename, *contents = NULL;
183 	gchar **locations;
184 	gint row;
185 	GError *error = NULL;
186 
187 	g_return_if_fail (GTK_IS_ENTRY (entry));
188 
189 	completion = gtk_entry_get_completion (entry);
190 	g_return_if_fail (completion != NULL);
191 
192 	filename = ecepp_location_get_locations_filename (FALSE);
193 
194 	if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
195 		g_free (filename);
196 		return;
197 	}
198 
199 	if (!g_file_get_contents (filename, &contents, NULL, &error)) {
200 		if (error != NULL) {
201 			g_warning (
202 				"%s: Failed to load locations list '%s': %s",
203 				G_STRFUNC, filename, error->message);
204 			g_error_free (error);
205 		}
206 
207 		g_free (filename);
208 		return;
209 	}
210 
211 	locations = g_strsplit (contents, "\n", 0);
212 	if (!locations) {
213 		g_free (contents);
214 		g_free (filename);
215 		return;
216 	}
217 
218 	row = 0;
219 	store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion));
220 	while (locations[row] && *locations[row]) {
221 		GtkTreeIter iter;
222 		gtk_list_store_append (store, &iter);
223 		gtk_list_store_set (store, &iter, 0, locations[row], -1);
224 		row++;
225 	}
226 
227 	g_strfreev (locations);
228 	g_free (contents);
229 	g_free (filename);
230 }
231 
232 static void
ecepp_location_save_list(GtkEntry * entry)233 ecepp_location_save_list (GtkEntry *entry)
234 {
235 	GtkEntryCompletion *completion;
236 	GtkTreeModel *model;
237 	GtkTreeIter iter;
238 	const gchar *current_location;
239 	gchar *filename, *stored_content = NULL;
240 	gboolean needs_save = TRUE;
241 	GString *contents;
242 	GError *error = NULL;
243 
244 	g_return_if_fail (GTK_IS_ENTRY (entry));
245 
246 	completion = gtk_entry_get_completion (entry);
247 	g_return_if_fail (completion != NULL);
248 
249 	filename = ecepp_location_get_locations_filename (TRUE);
250 
251 	if (!g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
252 		gint r = g_mkdir_with_parents (filename, 0700);
253 		if (r < 0) {
254 			g_warning ("%s: Failed to create %s: %s", G_STRFUNC, filename, g_strerror (errno));
255 			g_free (filename);
256 			return;
257 		}
258 	}
259 
260 	g_free (filename);
261 
262 	filename = ecepp_location_get_locations_filename (FALSE);
263 	current_location = gtk_entry_get_text (entry);
264 
265 	/* Put current locatin on the very top of the list */
266 	contents = g_string_new (current_location);
267 	if (contents->len > 0)
268 		g_string_append_c (contents, '\n');
269 
270 	model = gtk_entry_completion_get_model (completion);
271 	if (gtk_tree_model_get_iter_first (model, &iter)) {
272 		gint i = 0;
273 		do {
274 			gchar *str;
275 
276 			gtk_tree_model_get (model, &iter, 0, &str, -1);
277 
278 			/* Skip the current location */
279 			if (str && *str && g_ascii_strcasecmp (str, current_location) != 0)
280 				g_string_append_printf (contents, "%s\n", str);
281 
282 			g_free (str);
283 
284 			i++;
285 
286 		} while (gtk_tree_model_iter_next (model, &iter) && (i < 20));
287 	}
288 
289 	if (g_file_get_contents (filename, &stored_content, NULL, NULL)) {
290 		needs_save = g_strcmp0 (stored_content, contents->str) != 0;
291 		g_free (stored_content);
292 	}
293 
294 	if (needs_save) {
295 		g_file_set_contents (filename, contents->str, -1, &error);
296 		if (error != NULL) {
297 			g_warning (
298 				"%s: Failed to save locations '%s': %s",
299 				G_STRFUNC, filename, error->message);
300 			g_error_free (error);
301 		}
302 	}
303 
304 	g_string_free (contents, TRUE);
305 	g_free (filename);
306 }
307 
308 static gboolean
ecepp_location_text_to_icon_visible(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)309 ecepp_location_text_to_icon_visible (GBinding *binding,
310 				     const GValue *source_value,
311 				     GValue *target_value,
312 				     gpointer user_data)
313 {
314 	const gchar *text;
315 	gboolean icon_visible = FALSE;
316 
317 	text = g_value_get_string (source_value);
318 
319 	if (text && *text) {
320 		struct _schemas {
321 			const gchar *schema;
322 			gint len;
323 		} schemas[] = {
324 			{ "http:", 5 },
325 			{ "https:", 6 },
326 			{ "www.", 4 },
327 			{ "ftp:", 4 },
328 			{ "sip:", 4 },
329 			{ "tel:", 4 },
330 			{ "xmpp:", 5 }
331 		};
332 		gint ii;
333 
334 		for (ii = 0; ii < G_N_ELEMENTS (schemas); ii++) {
335 			if (g_ascii_strncasecmp (text, schemas[ii].schema, schemas[ii].len) == 0) {
336 				icon_visible = TRUE;
337 				break;
338 			}
339 		}
340 	}
341 
342 	g_value_set_boolean (target_value, icon_visible);
343 
344 	return TRUE;
345 }
346 
347 static void
ecepp_location_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)348 ecepp_location_create_widgets (ECompEditorPropertyPart *property_part,
349 			       GtkWidget **out_label_widget,
350 			       GtkWidget **out_edit_widget)
351 {
352 	ECompEditorPropertyPartClass *part_class;
353 	GtkEntryCompletion *completion;
354 	GtkListStore *list_store;
355 
356 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_LOCATION (property_part));
357 	g_return_if_fail (out_label_widget != NULL);
358 	g_return_if_fail (out_edit_widget != NULL);
359 
360 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_location_parent_class);
361 	g_return_if_fail (part_class != NULL);
362 	g_return_if_fail (part_class->create_widgets != NULL);
363 
364 	*out_label_widget = NULL;
365 
366 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
367 
368 	g_return_if_fail (*out_label_widget == NULL);
369 	g_return_if_fail (*out_edit_widget != NULL);
370 
371 	completion = gtk_entry_completion_new ();
372 
373 	list_store = gtk_list_store_new (1, G_TYPE_STRING);
374 	gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (list_store));
375 	gtk_entry_completion_set_text_column (completion, 0);
376 
377 	gtk_entry_set_completion (GTK_ENTRY (*out_edit_widget), completion);
378 	g_object_unref (completion);
379 
380 	e_binding_bind_property_full (
381 		*out_edit_widget, "text",
382 		*out_edit_widget, "icon-visible",
383 		G_BINDING_SYNC_CREATE,
384 		ecepp_location_text_to_icon_visible,
385 		NULL, NULL, NULL);
386 
387 	*out_label_widget = gtk_label_new_with_mnemonic (C_("ECompEditor", "_Location:"));
388 	gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
389 
390 	g_object_set (G_OBJECT (*out_label_widget),
391 		"hexpand", FALSE,
392 		"halign", GTK_ALIGN_END,
393 		"vexpand", FALSE,
394 		"valign", GTK_ALIGN_CENTER,
395 		NULL);
396 
397 	gtk_widget_show (*out_label_widget);
398 
399 	ecepp_location_load_list (GTK_ENTRY (*out_edit_widget));
400 }
401 
402 static void
ecepp_location_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)403 ecepp_location_fill_component (ECompEditorPropertyPart *property_part,
404 			       ICalComponent *component)
405 {
406 	ECompEditorPropertyPartClass *part_class;
407 	GtkWidget *edit_widget;
408 
409 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_LOCATION (property_part));
410 
411 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_location_parent_class);
412 	g_return_if_fail (part_class != NULL);
413 	g_return_if_fail (part_class->fill_component != NULL);
414 
415 	part_class->fill_component (property_part, component);
416 
417 	edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
418 	g_return_if_fail (GTK_IS_ENTRY (edit_widget));
419 
420 	ecepp_location_save_list (GTK_ENTRY (edit_widget));
421 }
422 
423 static void
e_comp_editor_property_part_location_init(ECompEditorPropertyPartLocation * part_location)424 e_comp_editor_property_part_location_init (ECompEditorPropertyPartLocation *part_location)
425 {
426 }
427 
428 static void
e_comp_editor_property_part_location_class_init(ECompEditorPropertyPartLocationClass * klass)429 e_comp_editor_property_part_location_class_init (ECompEditorPropertyPartLocationClass *klass)
430 {
431 	ECompEditorPropertyPartStringClass *part_string_class;
432 	ECompEditorPropertyPartClass *part_class;
433 
434 	part_string_class = E_COMP_EDITOR_PROPERTY_PART_STRING_CLASS (klass);
435 	part_string_class->entry_type = E_TYPE_URL_ENTRY;
436 	part_string_class->prop_kind = I_CAL_LOCATION_PROPERTY;
437 	part_string_class->i_cal_new_func = i_cal_property_new_location;
438 	part_string_class->i_cal_set_func = i_cal_property_set_location;
439 	part_string_class->i_cal_get_func = i_cal_property_get_location;
440 
441 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
442 	part_class->create_widgets = ecepp_location_create_widgets;
443 	part_class->fill_component = ecepp_location_fill_component;
444 }
445 
446 ECompEditorPropertyPart *
e_comp_editor_property_part_location_new(EFocusTracker * focus_tracker)447 e_comp_editor_property_part_location_new (EFocusTracker *focus_tracker)
448 {
449 	ECompEditorPropertyPart *property_part;
450 
451 	property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_LOCATION, NULL);
452 
453 	e_comp_editor_property_part_string_attach_focus_tracker (
454 		E_COMP_EDITOR_PROPERTY_PART_STRING (property_part), focus_tracker);
455 
456 	return property_part;
457 }
458 
459 /* ************************************************************************* */
460 
461 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_CATEGORIES \
462 	(e_comp_editor_property_part_categories_get_type ())
463 #define E_COMP_EDITOR_PROPERTY_PART_CATEGORIES(obj) \
464 	(G_TYPE_CHECK_INSTANCE_CAST \
465 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_CATEGORIES, ECompEditorPropertyPartCategories))
466 #define E_IS_COMP_EDITOR_PROPERTY_PART_CATEGORIES(obj) \
467 	(G_TYPE_CHECK_INSTANCE_TYPE \
468 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_CATEGORIES))
469 
470 typedef struct _ECompEditorPropertyPartCategories ECompEditorPropertyPartCategories;
471 typedef struct _ECompEditorPropertyPartCategoriesClass ECompEditorPropertyPartCategoriesClass;
472 
473 struct _ECompEditorPropertyPartCategories {
474 	ECompEditorPropertyPartString parent;
475 };
476 
477 struct _ECompEditorPropertyPartCategoriesClass {
478 	ECompEditorPropertyPartStringClass parent_class;
479 };
480 
481 GType e_comp_editor_property_part_categories_get_type (void) G_GNUC_CONST;
482 
G_DEFINE_TYPE(ECompEditorPropertyPartCategories,e_comp_editor_property_part_categories,E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)483 G_DEFINE_TYPE (ECompEditorPropertyPartCategories, e_comp_editor_property_part_categories, E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)
484 
485 static void
486 ecepp_categories_button_clicked_cb (GtkButton *button,
487 				    GtkEntry *entry)
488 {
489 	g_return_if_fail (GTK_IS_ENTRY (entry));
490 
491 	e_categories_config_open_dialog_for_entry (entry);
492 }
493 
494 static void
ecepp_categories_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)495 ecepp_categories_create_widgets (ECompEditorPropertyPart *property_part,
496 				 GtkWidget **out_label_widget,
497 				 GtkWidget **out_edit_widget)
498 {
499 	ECompEditorPropertyPartClass *part_class;
500 	GtkEntryCompletion *completion;
501 	GtkWidget *button;
502 
503 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_CATEGORIES (property_part));
504 	g_return_if_fail (out_label_widget != NULL);
505 	g_return_if_fail (out_edit_widget != NULL);
506 
507 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_categories_parent_class);
508 	g_return_if_fail (part_class != NULL);
509 	g_return_if_fail (part_class->create_widgets != NULL);
510 
511 	*out_label_widget = NULL;
512 
513 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
514 	g_return_if_fail (*out_label_widget == NULL);
515 	g_return_if_fail (*out_edit_widget != NULL);
516 
517 	completion = e_category_completion_new ();
518 	gtk_entry_set_completion (GTK_ENTRY (*out_edit_widget), completion);
519 	g_object_unref (completion);
520 
521 	button = gtk_button_new_with_mnemonic (C_("ECompEditor", "_Categories…"));
522 	g_signal_connect (button, "clicked", G_CALLBACK (ecepp_categories_button_clicked_cb), *out_edit_widget);
523 
524 	*out_label_widget = button;
525 
526 	g_object_set (G_OBJECT (*out_label_widget),
527 		"hexpand", FALSE,
528 		"halign", GTK_ALIGN_END,
529 		"vexpand", FALSE,
530 		"valign", GTK_ALIGN_CENTER,
531 		NULL);
532 
533 	gtk_widget_show (*out_label_widget);
534 }
535 
536 static void
e_comp_editor_property_part_categories_init(ECompEditorPropertyPartCategories * part_categories)537 e_comp_editor_property_part_categories_init (ECompEditorPropertyPartCategories *part_categories)
538 {
539 	e_comp_editor_property_part_string_set_is_multivalue (
540 		E_COMP_EDITOR_PROPERTY_PART_STRING (part_categories), TRUE);
541 }
542 
543 static void
e_comp_editor_property_part_categories_class_init(ECompEditorPropertyPartCategoriesClass * klass)544 e_comp_editor_property_part_categories_class_init (ECompEditorPropertyPartCategoriesClass *klass)
545 {
546 	ECompEditorPropertyPartStringClass *part_string_class;
547 	ECompEditorPropertyPartClass *part_class;
548 
549 	part_string_class = E_COMP_EDITOR_PROPERTY_PART_STRING_CLASS (klass);
550 	part_string_class->prop_kind = I_CAL_CATEGORIES_PROPERTY;
551 	part_string_class->i_cal_new_func = i_cal_property_new_categories;
552 	part_string_class->i_cal_set_func = i_cal_property_set_categories;
553 	part_string_class->i_cal_get_func = i_cal_property_get_categories;
554 
555 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
556 	part_class->create_widgets = ecepp_categories_create_widgets;
557 }
558 
559 ECompEditorPropertyPart *
e_comp_editor_property_part_categories_new(EFocusTracker * focus_tracker)560 e_comp_editor_property_part_categories_new (EFocusTracker *focus_tracker)
561 {
562 	ECompEditorPropertyPart *property_part;
563 
564 	property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_CATEGORIES, NULL);
565 
566 	e_comp_editor_property_part_string_attach_focus_tracker (
567 		E_COMP_EDITOR_PROPERTY_PART_STRING (property_part), focus_tracker);
568 
569 	return property_part;
570 }
571 
572 /* ************************************************************************* */
573 
574 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_DESCRIPTION \
575 	(e_comp_editor_property_part_description_get_type ())
576 #define E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION(obj) \
577 	(G_TYPE_CHECK_INSTANCE_CAST \
578 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DESCRIPTION, ECompEditorPropertyPartDescription))
579 #define E_IS_COMP_EDITOR_PROPERTY_PART_DESCRIPTION(obj) \
580 	(G_TYPE_CHECK_INSTANCE_TYPE \
581 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DESCRIPTION))
582 
583 typedef struct _ECompEditorPropertyPartDescription ECompEditorPropertyPartDescription;
584 typedef struct _ECompEditorPropertyPartDescriptionClass ECompEditorPropertyPartDescriptionClass;
585 
586 struct _ECompEditorPropertyPartDescription {
587 	ECompEditorPropertyPartString parent;
588 
589 	gboolean has_html;
590 	gboolean mode_html;
591 	gchar *alt_desc; /* X-ALT-DESC with text/html format */
592 	GtkWidget *real_edit_widget;
593 	GtkWidget *description_label;
594 	GtkWidget *view_as_label;
595 	GtkWidget *web_view_scrolled_window;
596 	GtkWidget *web_view;
597 };
598 
599 struct _ECompEditorPropertyPartDescriptionClass {
600 	ECompEditorPropertyPartStringClass parent_class;
601 };
602 
603 GType e_comp_editor_property_part_description_get_type (void) G_GNUC_CONST;
604 
G_DEFINE_TYPE(ECompEditorPropertyPartDescription,e_comp_editor_property_part_description,E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)605 G_DEFINE_TYPE (ECompEditorPropertyPartDescription, e_comp_editor_property_part_description, E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)
606 
607 static GtkWidget *
608 ecepp_description_get_real_edit_widget (ECompEditorPropertyPartString *part_string)
609 {
610 	g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (part_string), NULL);
611 
612 	return E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (part_string)->real_edit_widget;
613 }
614 
615 static void
ecepp_description_update_view_mode(ECompEditorPropertyPartDescription * description_part)616 ecepp_description_update_view_mode (ECompEditorPropertyPartDescription *description_part)
617 {
618 	if (description_part->has_html) {
619 		gchar *markup;
620 
621 		markup = g_markup_printf_escaped ("<a href=\"evo-switch-view-mode\">%s</a>",
622 			description_part->mode_html ?
623 			((description_part->description_label && gtk_widget_get_sensitive (description_part->description_label)) ?
624 			_("Edit as text") : _("View as text")) : _("View as HTML"));
625 
626 		gtk_label_set_markup (GTK_LABEL (description_part->view_as_label), markup);
627 
628 		g_free (markup);
629 
630 		gtk_widget_show (description_part->view_as_label);
631 
632 		if (description_part->mode_html) {
633 			if (description_part->alt_desc) {
634 				e_web_view_load_string (E_WEB_VIEW (description_part->web_view), description_part->alt_desc);
635 			} else {
636 				GtkTextBuffer *buffer;
637 				GtkTextIter text_iter_start, text_iter_end;
638 				GtkWidget *edit_widget;
639 				gchar *value;
640 
641 				edit_widget = e_comp_editor_property_part_string_get_real_edit_widget (E_COMP_EDITOR_PROPERTY_PART_STRING (description_part));
642 				g_return_if_fail (GTK_IS_TEXT_VIEW (edit_widget));
643 
644 				buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit_widget));
645 				gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
646 				gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
647 				value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
648 
649 				e_web_view_load_string (E_WEB_VIEW (description_part->web_view), value ? value : "");
650 
651 				g_free (value);
652 			}
653 
654 			gtk_widget_hide (description_part->real_edit_widget);
655 			gtk_widget_show (description_part->web_view_scrolled_window);
656 		} else {
657 			gtk_widget_hide (description_part->web_view_scrolled_window);
658 			gtk_widget_show (description_part->real_edit_widget);
659 		}
660 	} else {
661 		gtk_widget_hide (description_part->view_as_label);
662 		gtk_widget_hide (description_part->web_view_scrolled_window);
663 		gtk_widget_show (description_part->real_edit_widget);
664 	}
665 }
666 
667 static gboolean
ecepp_description_flip_view_as_cb(GtkLabel * label,const gchar * uri,gpointer user_data)668 ecepp_description_flip_view_as_cb (GtkLabel *label,
669 				   const gchar *uri,
670 				   gpointer user_data)
671 {
672 	ECompEditorPropertyPartDescription *description_part = user_data;
673 
674 	g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (description_part), FALSE);
675 
676 	description_part->mode_html = !description_part->mode_html;
677 
678 	ecepp_description_update_view_mode (description_part);
679 
680 	return TRUE;
681 }
682 
683 static void
ecepp_description_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)684 ecepp_description_create_widgets (ECompEditorPropertyPart *property_part,
685 				  GtkWidget **out_label_widget,
686 				  GtkWidget **out_edit_widget)
687 {
688 	ECompEditorPropertyPartClass *part_class;
689 	ECompEditorPropertyPartDescription *description_part;
690 	GtkTextView *text_view;
691 	GtkWidget *box, *label;
692 
693 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (property_part));
694 	g_return_if_fail (out_label_widget != NULL);
695 	g_return_if_fail (out_edit_widget != NULL);
696 
697 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_description_parent_class);
698 	g_return_if_fail (part_class != NULL);
699 	g_return_if_fail (part_class->create_widgets != NULL);
700 
701 	description_part = E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (property_part);
702 
703 	*out_label_widget = NULL;
704 
705 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
706 	g_return_if_fail (*out_label_widget == NULL);
707 	g_return_if_fail (*out_edit_widget != NULL);
708 
709 	description_part->real_edit_widget = *out_edit_widget;
710 
711 	label = gtk_label_new_with_mnemonic (C_("ECompEditor", "_Description:"));
712 	gtk_label_set_mnemonic_widget (GTK_LABEL (label), *out_edit_widget);
713 
714 	description_part->description_label = label;
715 
716 	text_view = GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (*out_edit_widget)));
717 	gtk_text_view_set_wrap_mode (text_view, GTK_WRAP_WORD);
718 	gtk_text_view_set_monospace (text_view, TRUE);
719 	e_buffer_tagger_connect (text_view);
720 	e_spell_text_view_attach (text_view);
721 
722 	g_object_set (G_OBJECT (label),
723 		"hexpand", FALSE,
724 		"halign", GTK_ALIGN_END,
725 		"vexpand", FALSE,
726 		"valign", GTK_ALIGN_START,
727 		NULL);
728 
729 	g_object_set (G_OBJECT (*out_edit_widget),
730 		"hexpand", TRUE,
731 		"halign", GTK_ALIGN_FILL,
732 		"vexpand", TRUE,
733 		"valign", GTK_ALIGN_FILL,
734 		"height-request", 100,
735 		NULL);
736 
737 	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
738 
739 	g_object_set (G_OBJECT (box),
740 		"hexpand", FALSE,
741 		"halign", GTK_ALIGN_END,
742 		"vexpand", FALSE,
743 		"valign", GTK_ALIGN_START,
744 		NULL);
745 
746 	gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
747 
748 	description_part->view_as_label = gtk_label_new ("");
749 
750 	g_object_set (G_OBJECT (description_part->view_as_label),
751 		"hexpand", FALSE,
752 		"halign", GTK_ALIGN_END,
753 		"vexpand", FALSE,
754 		"valign", GTK_ALIGN_START,
755 		"track-visited-links", FALSE,
756 		NULL);
757 
758 	g_signal_connect (description_part->view_as_label, "activate-link",
759 		G_CALLBACK (ecepp_description_flip_view_as_cb), description_part);
760 
761 	gtk_box_pack_start (GTK_BOX (box), description_part->view_as_label, FALSE, FALSE, 0);
762 
763 	gtk_widget_show_all (box);
764 
765 	*out_label_widget = box;
766 
767 	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
768 
769 	g_object_set (G_OBJECT (box),
770 		"hexpand", TRUE,
771 		"halign", GTK_ALIGN_FILL,
772 		"vexpand", TRUE,
773 		"valign", GTK_ALIGN_FILL,
774 		"visible", TRUE,
775 		NULL);
776 
777 	gtk_box_pack_start (GTK_BOX (box), description_part->real_edit_widget, TRUE, TRUE, 0);
778 
779 	description_part->web_view = e_web_view_new ();
780 	description_part->web_view_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
781 
782 	gtk_container_add (GTK_CONTAINER (description_part->web_view_scrolled_window), description_part->web_view);
783 
784 	g_object_set (G_OBJECT (description_part->web_view),
785 		"hexpand", TRUE,
786 		"halign", GTK_ALIGN_FILL,
787 		"vexpand", TRUE,
788 		"valign", GTK_ALIGN_FILL,
789 		"visible", TRUE,
790 		NULL);
791 
792 	g_object_set (G_OBJECT (description_part->web_view_scrolled_window),
793 		"hexpand", TRUE,
794 		"halign", GTK_ALIGN_FILL,
795 		"vexpand", TRUE,
796 		"valign", GTK_ALIGN_FILL,
797 		"shadow-type", GTK_SHADOW_IN,
798 		"hscrollbar-policy", GTK_POLICY_AUTOMATIC,
799 		"vscrollbar-policy", GTK_POLICY_AUTOMATIC,
800 		"visible", FALSE,
801 		NULL);
802 
803 	gtk_box_pack_start (GTK_BOX (box), description_part->web_view_scrolled_window, TRUE, TRUE, 0);
804 
805 	*out_edit_widget = box;
806 }
807 
808 static gboolean
ecepp_description_contains_html(const gchar * value)809 ecepp_description_contains_html (const gchar *value)
810 {
811 	if (!value || !*value)
812 		return FALSE;
813 
814 	return camel_strstrcase (value, "<html>") ||
815 		camel_strstrcase (value, "<body>") ||
816 		camel_strstrcase (value, "<br>") ||
817 		camel_strstrcase (value, "<span>") ||
818 		camel_strstrcase (value, "<b>") ||
819 		camel_strstrcase (value, "<i>") ||
820 		camel_strstrcase (value, "<u>") ||
821 		camel_strstrcase (value, "&nbsp;") ||
822 		camel_strstrcase (value, "<ul>") ||
823 		camel_strstrcase (value, "<li>") ||
824 		camel_strstrcase (value, "</a>");
825 }
826 
827 static void
ecepp_description_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)828 ecepp_description_fill_widget (ECompEditorPropertyPart *property_part,
829 			       ICalComponent *component)
830 {
831 	ECompEditorPropertyPartClass *part_class;
832 	ECompEditorPropertyPartDescription *description_part;
833 	GtkTextBuffer *buffer;
834 	GtkTextIter text_iter_start, text_iter_end;
835 	GtkWidget *edit_widget;
836 	gchar *value;
837 
838 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (property_part));
839 	g_return_if_fail (I_CAL_IS_COMPONENT (component));
840 
841 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_description_parent_class);
842 	g_return_if_fail (part_class != NULL);
843 	g_return_if_fail (part_class->fill_widget != NULL);
844 
845 	description_part = E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (property_part);
846 
847 	part_class->fill_widget (property_part, component);
848 
849 	edit_widget = e_comp_editor_property_part_string_get_real_edit_widget (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
850 	g_return_if_fail (GTK_IS_TEXT_VIEW (edit_widget));
851 
852 	e_buffer_tagger_update_tags (GTK_TEXT_VIEW (edit_widget));
853 
854 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit_widget));
855 	gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
856 	gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
857 	value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
858 
859 	g_clear_pointer (&description_part->alt_desc, g_free);
860 
861 	description_part->has_html = ecepp_description_contains_html (value);
862 
863 	if (!description_part->has_html && value && *value) {
864 		ICalProperty *prop;
865 
866 		for (prop = i_cal_component_get_first_property (component, I_CAL_X_PROPERTY);
867 		     prop;
868 		     g_object_unref (prop), prop = i_cal_component_get_next_property (component, I_CAL_X_PROPERTY)) {
869 			if (i_cal_property_get_x_name (prop) && g_ascii_strcasecmp (i_cal_property_get_x_name (prop), "X-ALT-DESC") == 0) {
870 				ICalParameter *param;
871 
872 				param = i_cal_property_get_first_parameter (prop, I_CAL_FMTTYPE_PARAMETER);
873 
874 				if (param && i_cal_parameter_get_fmttype (param) &&
875 				    g_ascii_strcasecmp (i_cal_parameter_get_fmttype (param), "text/html") == 0) {
876 					ICalValue *value;
877 					const gchar *str = NULL;
878 
879 					value = i_cal_property_get_value (prop);
880 
881 					if (value)
882 						str = i_cal_value_get_x (value);
883 
884 					if (str && *str) {
885 						description_part->alt_desc = g_strdup (str);
886 					}
887 
888 					g_clear_object (&value);
889 				}
890 
891 				g_clear_object (&param);
892 
893 				if (description_part->alt_desc) {
894 					description_part->has_html = TRUE;
895 					g_object_unref (prop);
896 					break;
897 				}
898 			}
899 		}
900 	}
901 
902 	ecepp_description_update_view_mode (description_part);
903 
904 	g_free (value);
905 }
906 
907 static void
ecepp_description_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)908 ecepp_description_fill_component (ECompEditorPropertyPart *property_part,
909 				  ICalComponent *component)
910 {
911 	ECompEditorPropertyPartClass *part_class;
912 
913 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_description_parent_class);
914 	g_return_if_fail (part_class != NULL);
915 	g_return_if_fail (part_class->fill_component != NULL);
916 
917 	part_class->fill_component (property_part, component);
918 
919 	while (e_cal_util_component_remove_x_property (component, "X-ALT-DESC")) {
920 		/* Remove all of them, not only text/html, they are obsolete now */
921 	}
922 }
923 
924 static void
ecepp_description_sensitize_widgets(ECompEditorPropertyPart * property_part,gboolean force_insensitive)925 ecepp_description_sensitize_widgets (ECompEditorPropertyPart *property_part,
926 				     gboolean force_insensitive)
927 {
928 	ECompEditorPropertyPartDescription *description_part;
929 	GtkWidget *widget;
930 
931 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (property_part));
932 
933 	description_part = E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (property_part);
934 
935 	if (description_part->description_label)
936 		gtk_widget_set_sensitive (description_part->description_label, !force_insensitive);
937 
938 	widget = e_comp_editor_property_part_string_get_real_edit_widget (E_COMP_EDITOR_PROPERTY_PART_STRING (description_part));
939 	if (widget)
940 		g_object_set (G_OBJECT (widget), "editable", !force_insensitive, NULL);
941 
942 	ecepp_description_update_view_mode (description_part);
943 }
944 
945 static void
ecepp_description_dispose(GObject * object)946 ecepp_description_dispose (GObject *object)
947 {
948 	ECompEditorPropertyPartDescription *description_part = E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION (object);
949 
950 	g_clear_pointer (&description_part->alt_desc, g_free);
951 
952 	G_OBJECT_CLASS (e_comp_editor_property_part_description_parent_class)->dispose (object);
953 }
954 
955 static void
e_comp_editor_property_part_description_init(ECompEditorPropertyPartDescription * part_description)956 e_comp_editor_property_part_description_init (ECompEditorPropertyPartDescription *part_description)
957 {
958 	part_description->mode_html = TRUE;
959 }
960 
961 static void
e_comp_editor_property_part_description_class_init(ECompEditorPropertyPartDescriptionClass * klass)962 e_comp_editor_property_part_description_class_init (ECompEditorPropertyPartDescriptionClass *klass)
963 {
964 	ECompEditorPropertyPartStringClass *part_string_class;
965 	ECompEditorPropertyPartClass *part_class;
966 	GObjectClass *object_class;
967 
968 	part_string_class = E_COMP_EDITOR_PROPERTY_PART_STRING_CLASS (klass);
969 	part_string_class->entry_type = GTK_TYPE_TEXT_VIEW;
970 	part_string_class->prop_kind = I_CAL_DESCRIPTION_PROPERTY;
971 	part_string_class->i_cal_new_func = i_cal_property_new_description;
972 	part_string_class->i_cal_set_func = i_cal_property_set_description;
973 	part_string_class->i_cal_get_func = i_cal_property_get_description;
974 	part_string_class->get_real_edit_widget = ecepp_description_get_real_edit_widget;
975 
976 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
977 	part_class->create_widgets = ecepp_description_create_widgets;
978 	part_class->fill_widget = ecepp_description_fill_widget;
979 	part_class->fill_component = ecepp_description_fill_component;
980 	part_class->sensitize_widgets = ecepp_description_sensitize_widgets;
981 
982 	object_class = G_OBJECT_CLASS (klass);
983 	object_class->dispose = ecepp_description_dispose;
984 }
985 
986 ECompEditorPropertyPart *
e_comp_editor_property_part_description_new(EFocusTracker * focus_tracker)987 e_comp_editor_property_part_description_new (EFocusTracker *focus_tracker)
988 {
989 	ECompEditorPropertyPart *property_part;
990 
991 	property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_DESCRIPTION, NULL);
992 
993 	e_comp_editor_property_part_string_attach_focus_tracker (
994 		E_COMP_EDITOR_PROPERTY_PART_STRING (property_part), focus_tracker);
995 
996 	return property_part;
997 }
998 
999 /* ************************************************************************* */
1000 
1001 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_URL \
1002 	(e_comp_editor_property_part_url_get_type ())
1003 #define E_COMP_EDITOR_PROPERTY_PART_URL(obj) \
1004 	(G_TYPE_CHECK_INSTANCE_CAST \
1005 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_URL, ECompEditorPropertyPartUrl))
1006 #define E_IS_COMP_EDITOR_PROPERTY_PART_URL(obj) \
1007 	(G_TYPE_CHECK_INSTANCE_TYPE \
1008 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_URL))
1009 
1010 typedef struct _ECompEditorPropertyPartUrl ECompEditorPropertyPartUrl;
1011 typedef struct _ECompEditorPropertyPartUrlClass ECompEditorPropertyPartUrlClass;
1012 
1013 struct _ECompEditorPropertyPartUrl {
1014 	ECompEditorPropertyPartString parent;
1015 };
1016 
1017 struct _ECompEditorPropertyPartUrlClass {
1018 	ECompEditorPropertyPartStringClass parent_class;
1019 };
1020 
1021 GType e_comp_editor_property_part_url_get_type (void) G_GNUC_CONST;
1022 
G_DEFINE_TYPE(ECompEditorPropertyPartUrl,e_comp_editor_property_part_url,E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)1023 G_DEFINE_TYPE (ECompEditorPropertyPartUrl, e_comp_editor_property_part_url, E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING)
1024 
1025 static void
1026 ecepp_url_create_widgets (ECompEditorPropertyPart *property_part,
1027 			  GtkWidget **out_label_widget,
1028 			  GtkWidget **out_edit_widget)
1029 {
1030 	ECompEditorPropertyPartClass *part_class;
1031 
1032 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_URL (property_part));
1033 	g_return_if_fail (out_label_widget != NULL);
1034 	g_return_if_fail (out_edit_widget != NULL);
1035 
1036 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_url_parent_class);
1037 	g_return_if_fail (part_class != NULL);
1038 	g_return_if_fail (part_class->create_widgets != NULL);
1039 
1040 	*out_label_widget = NULL;
1041 
1042 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
1043 	g_return_if_fail (*out_label_widget == NULL);
1044 	g_return_if_fail (*out_edit_widget != NULL);
1045 
1046 	*out_label_widget = gtk_label_new_with_mnemonic (C_("ECompEditor", "_Web page:"));
1047 	gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
1048 
1049 	g_object_set (G_OBJECT (*out_label_widget),
1050 		"hexpand", FALSE,
1051 		"halign", GTK_ALIGN_END,
1052 		"vexpand", FALSE,
1053 		"valign", GTK_ALIGN_CENTER,
1054 		NULL);
1055 
1056 	gtk_widget_show (*out_label_widget);
1057 }
1058 
1059 static void
e_comp_editor_property_part_url_init(ECompEditorPropertyPartUrl * part_url)1060 e_comp_editor_property_part_url_init (ECompEditorPropertyPartUrl *part_url)
1061 {
1062 }
1063 
1064 static void
e_comp_editor_property_part_url_class_init(ECompEditorPropertyPartUrlClass * klass)1065 e_comp_editor_property_part_url_class_init (ECompEditorPropertyPartUrlClass *klass)
1066 {
1067 	ECompEditorPropertyPartStringClass *part_string_class;
1068 	ECompEditorPropertyPartClass *part_class;
1069 
1070 	part_string_class = E_COMP_EDITOR_PROPERTY_PART_STRING_CLASS (klass);
1071 	part_string_class->entry_type = E_TYPE_URL_ENTRY;
1072 	part_string_class->prop_kind = I_CAL_URL_PROPERTY;
1073 	part_string_class->i_cal_new_func = i_cal_property_new_url;
1074 	part_string_class->i_cal_set_func = i_cal_property_set_url;
1075 	part_string_class->i_cal_get_func = i_cal_property_get_url;
1076 
1077 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1078 	part_class->create_widgets = ecepp_url_create_widgets;
1079 }
1080 
1081 ECompEditorPropertyPart *
e_comp_editor_property_part_url_new(EFocusTracker * focus_tracker)1082 e_comp_editor_property_part_url_new (EFocusTracker *focus_tracker)
1083 {
1084 	ECompEditorPropertyPart *property_part;
1085 
1086 	property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_URL, NULL);
1087 
1088 	e_comp_editor_property_part_string_attach_focus_tracker (
1089 		E_COMP_EDITOR_PROPERTY_PART_STRING (property_part), focus_tracker);
1090 
1091 	return property_part;
1092 }
1093 
1094 /* ************************************************************************* */
1095 
1096 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED \
1097 	(e_comp_editor_property_part_datetime_labeled_get_type ())
1098 #define E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED(obj) \
1099 	(G_TYPE_CHECK_INSTANCE_CAST \
1100 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED, ECompEditorPropertyPartDatetimeLabeled))
1101 #define E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED(obj) \
1102 	(G_TYPE_CHECK_INSTANCE_TYPE \
1103 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED))
1104 
1105 typedef struct _ECompEditorPropertyPartDatetimeLabeled ECompEditorPropertyPartDatetimeLabeled;
1106 typedef struct _ECompEditorPropertyPartDatetimeLabeledClass ECompEditorPropertyPartDatetimeLabeledClass;
1107 
1108 struct _ECompEditorPropertyPartDatetimeLabeled {
1109 	ECompEditorPropertyPartDatetime parent;
1110 
1111 	gchar *label;
1112 };
1113 
1114 struct _ECompEditorPropertyPartDatetimeLabeledClass {
1115 	ECompEditorPropertyPartDatetimeClass parent_class;
1116 };
1117 
1118 GType e_comp_editor_property_part_datetime_labeled_get_type (void) G_GNUC_CONST;
1119 
1120 enum {
1121 	DATETIME_LABELED_PROP_0,
1122 	DATETIME_LABELED_PROP_LABEL
1123 };
1124 
G_DEFINE_ABSTRACT_TYPE(ECompEditorPropertyPartDatetimeLabeled,e_comp_editor_property_part_datetime_labeled,E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME)1125 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartDatetimeLabeled, e_comp_editor_property_part_datetime_labeled, E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME)
1126 
1127 static void
1128 ecepp_datetime_labeled_create_widgets (ECompEditorPropertyPart *property_part,
1129 				       GtkWidget **out_label_widget,
1130 				       GtkWidget **out_edit_widget)
1131 {
1132 	ECompEditorPropertyPartDatetimeLabeled *part_datetime_labeled;
1133 	ECompEditorPropertyPartClass *part_class;
1134 
1135 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (property_part));
1136 	g_return_if_fail (out_label_widget != NULL);
1137 	g_return_if_fail (out_edit_widget != NULL);
1138 
1139 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_datetime_labeled_parent_class);
1140 	g_return_if_fail (part_class != NULL);
1141 	g_return_if_fail (part_class->create_widgets != NULL);
1142 
1143 	part_datetime_labeled = E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (property_part);
1144 
1145 	*out_label_widget = NULL;
1146 
1147 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
1148 	g_return_if_fail (*out_label_widget == NULL);
1149 	g_return_if_fail (*out_edit_widget != NULL);
1150 
1151 	*out_label_widget = gtk_label_new_with_mnemonic (part_datetime_labeled->label);
1152 	gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
1153 
1154 	g_object_set (G_OBJECT (*out_label_widget),
1155 		"hexpand", FALSE,
1156 		"halign", GTK_ALIGN_END,
1157 		"vexpand", FALSE,
1158 		"valign", GTK_ALIGN_CENTER,
1159 		NULL);
1160 
1161 	gtk_widget_show (*out_label_widget);
1162 }
1163 
1164 static void
ecepp_datetime_labeled_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)1165 ecepp_datetime_labeled_set_property (GObject *object,
1166 				     guint property_id,
1167 				     const GValue *value,
1168 				     GParamSpec *pspec)
1169 {
1170 	ECompEditorPropertyPartDatetimeLabeled *part_datetime_labeled;
1171 
1172 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (object));
1173 
1174 	part_datetime_labeled = E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (object);
1175 
1176 	switch (property_id) {
1177 		case DATETIME_LABELED_PROP_LABEL:
1178 			g_free (part_datetime_labeled->label);
1179 			part_datetime_labeled->label = g_value_dup_string (value);
1180 			return;
1181 	}
1182 
1183 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1184 }
1185 
1186 static void
ecepp_datetime_labeled_finalize(GObject * object)1187 ecepp_datetime_labeled_finalize (GObject *object)
1188 {
1189 	ECompEditorPropertyPartDatetimeLabeled *part_datetime_labeled;
1190 
1191 	part_datetime_labeled = E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (object);
1192 
1193 	g_free (part_datetime_labeled->label);
1194 	part_datetime_labeled->label = NULL;
1195 
1196 	G_OBJECT_CLASS (e_comp_editor_property_part_datetime_labeled_parent_class)->finalize (object);
1197 }
1198 
1199 static void
e_comp_editor_property_part_datetime_labeled_init(ECompEditorPropertyPartDatetimeLabeled * part_datetime_labeled)1200 e_comp_editor_property_part_datetime_labeled_init (ECompEditorPropertyPartDatetimeLabeled *part_datetime_labeled)
1201 {
1202 }
1203 
1204 static void
e_comp_editor_property_part_datetime_labeled_class_init(ECompEditorPropertyPartDatetimeLabeledClass * klass)1205 e_comp_editor_property_part_datetime_labeled_class_init (ECompEditorPropertyPartDatetimeLabeledClass *klass)
1206 {
1207 	ECompEditorPropertyPartClass *part_class;
1208 	GObjectClass *object_class;
1209 
1210 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1211 	part_class->create_widgets = ecepp_datetime_labeled_create_widgets;
1212 
1213 	object_class = G_OBJECT_CLASS (klass);
1214 	object_class->set_property = ecepp_datetime_labeled_set_property;
1215 	object_class->finalize = ecepp_datetime_labeled_finalize;
1216 
1217 	g_object_class_install_property (
1218 		object_class,
1219 		DATETIME_LABELED_PROP_LABEL,
1220 		g_param_spec_string (
1221 			"label",
1222 			"Label",
1223 			"Label of the datetime",
1224 			NULL,
1225 			G_PARAM_WRITABLE |
1226 			G_PARAM_CONSTRUCT_ONLY |
1227 			G_PARAM_STATIC_STRINGS));
1228 }
1229 
1230 static void
e_comp_editor_property_part_datetime_labeled_setup(ECompEditorPropertyPartDatetimeLabeled * part_datetime_labeled,gboolean date_only,gboolean allow_no_date_set)1231 e_comp_editor_property_part_datetime_labeled_setup (ECompEditorPropertyPartDatetimeLabeled *part_datetime_labeled,
1232 						    gboolean date_only,
1233 						    gboolean allow_no_date_set)
1234 {
1235 	ECompEditorPropertyPartDatetime *part_datetime;
1236 
1237 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (part_datetime_labeled));
1238 
1239 	part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime_labeled);
1240 
1241 	e_comp_editor_property_part_datetime_set_date_only (part_datetime, date_only);
1242 	e_comp_editor_property_part_datetime_set_allow_no_date_set (part_datetime, allow_no_date_set);
1243 }
1244 
1245 /* ************************************************************************* */
1246 
1247 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_DTSTART \
1248 	(e_comp_editor_property_part_dtstart_get_type ())
1249 #define E_COMP_EDITOR_PROPERTY_PART_DTSTART(obj) \
1250 	(G_TYPE_CHECK_INSTANCE_CAST \
1251 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DTSTART, ECompEditorPropertyPartDtstart))
1252 #define E_IS_COMP_EDITOR_PROPERTY_PART_DTSTART(obj) \
1253 	(G_TYPE_CHECK_INSTANCE_TYPE \
1254 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DTSTART))
1255 
1256 typedef struct _ECompEditorPropertyPartDtstart ECompEditorPropertyPartDtstart;
1257 typedef struct _ECompEditorPropertyPartDtstartClass ECompEditorPropertyPartDtstartClass;
1258 
1259 struct _ECompEditorPropertyPartDtstart {
1260 	ECompEditorPropertyPartDatetimeLabeled parent;
1261 };
1262 
1263 struct _ECompEditorPropertyPartDtstartClass {
1264 	ECompEditorPropertyPartDatetimeLabeledClass parent_class;
1265 };
1266 
1267 GType e_comp_editor_property_part_dtstart_get_type (void) G_GNUC_CONST;
1268 
G_DEFINE_TYPE(ECompEditorPropertyPartDtstart,e_comp_editor_property_part_dtstart,E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)1269 G_DEFINE_TYPE (ECompEditorPropertyPartDtstart, e_comp_editor_property_part_dtstart, E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)
1270 
1271 static void
1272 e_comp_editor_property_part_dtstart_init (ECompEditorPropertyPartDtstart *part_dtstart)
1273 {
1274 }
1275 
1276 static void
e_comp_editor_property_part_dtstart_class_init(ECompEditorPropertyPartDtstartClass * klass)1277 e_comp_editor_property_part_dtstart_class_init (ECompEditorPropertyPartDtstartClass *klass)
1278 {
1279 	ECompEditorPropertyPartDatetimeClass *part_datetime_class;
1280 
1281 	part_datetime_class = E_COMP_EDITOR_PROPERTY_PART_DATETIME_CLASS (klass);
1282 	part_datetime_class->prop_kind = I_CAL_DTSTART_PROPERTY;
1283 	part_datetime_class->i_cal_new_func = i_cal_property_new_dtstart;
1284 	part_datetime_class->i_cal_set_func = i_cal_property_set_dtstart;
1285 	part_datetime_class->i_cal_get_func = i_cal_property_get_dtstart;
1286 }
1287 
1288 ECompEditorPropertyPart *
e_comp_editor_property_part_dtstart_new(const gchar * label,gboolean date_only,gboolean allow_no_date_set)1289 e_comp_editor_property_part_dtstart_new (const gchar *label,
1290 					 gboolean date_only,
1291 					 gboolean allow_no_date_set)
1292 {
1293 	ECompEditorPropertyPart *part;
1294 
1295 	part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_DTSTART,
1296 		"label", label,
1297 		NULL);
1298 
1299 	e_comp_editor_property_part_datetime_labeled_setup (
1300 		E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (part),
1301 		date_only, allow_no_date_set);
1302 
1303 	return part;
1304 }
1305 
1306 /* ************************************************************************* */
1307 
1308 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_DTEND \
1309 	(e_comp_editor_property_part_dtend_get_type ())
1310 #define E_COMP_EDITOR_PROPERTY_PART_DTEND(obj) \
1311 	(G_TYPE_CHECK_INSTANCE_CAST \
1312 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DTEND, ECompEditorPropertyPartDtend))
1313 #define E_IS_COMP_EDITOR_PROPERTY_PART_DTEND(obj) \
1314 	(G_TYPE_CHECK_INSTANCE_TYPE \
1315 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DTEND))
1316 
1317 typedef struct _ECompEditorPropertyPartDtend ECompEditorPropertyPartDtend;
1318 typedef struct _ECompEditorPropertyPartDtendClass ECompEditorPropertyPartDtendClass;
1319 
1320 struct _ECompEditorPropertyPartDtend {
1321 	ECompEditorPropertyPartDatetimeLabeled parent;
1322 };
1323 
1324 struct _ECompEditorPropertyPartDtendClass {
1325 	ECompEditorPropertyPartDatetimeLabeledClass parent_class;
1326 };
1327 
1328 GType e_comp_editor_property_part_dtend_get_type (void) G_GNUC_CONST;
1329 
G_DEFINE_TYPE(ECompEditorPropertyPartDtend,e_comp_editor_property_part_dtend,E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)1330 G_DEFINE_TYPE (ECompEditorPropertyPartDtend, e_comp_editor_property_part_dtend, E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)
1331 
1332 static void
1333 e_comp_editor_property_part_dtend_init (ECompEditorPropertyPartDtend *part_dtend)
1334 {
1335 }
1336 
1337 static void
e_comp_editor_property_part_dtend_class_init(ECompEditorPropertyPartDtendClass * klass)1338 e_comp_editor_property_part_dtend_class_init (ECompEditorPropertyPartDtendClass *klass)
1339 {
1340 	ECompEditorPropertyPartDatetimeClass *part_datetime_class;
1341 
1342 	part_datetime_class = E_COMP_EDITOR_PROPERTY_PART_DATETIME_CLASS (klass);
1343 	part_datetime_class->prop_kind = I_CAL_DTEND_PROPERTY;
1344 	part_datetime_class->i_cal_new_func = i_cal_property_new_dtend;
1345 	part_datetime_class->i_cal_set_func = i_cal_property_set_dtend;
1346 	part_datetime_class->i_cal_get_func = i_cal_property_get_dtend;
1347 }
1348 
1349 ECompEditorPropertyPart *
e_comp_editor_property_part_dtend_new(const gchar * label,gboolean date_only,gboolean allow_no_date_set)1350 e_comp_editor_property_part_dtend_new (const gchar *label,
1351 				       gboolean date_only,
1352 				       gboolean allow_no_date_set)
1353 {
1354 	ECompEditorPropertyPart *part;
1355 
1356 	part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_DTEND,
1357 		"label", label,
1358 		NULL);
1359 
1360 	e_comp_editor_property_part_datetime_labeled_setup (
1361 		E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (part),
1362 		date_only, allow_no_date_set);
1363 
1364 	return part;
1365 }
1366 
1367 /* ************************************************************************* */
1368 
1369 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_DUE \
1370 	(e_comp_editor_property_part_due_get_type ())
1371 #define E_COMP_EDITOR_PROPERTY_PART_DUE(obj) \
1372 	(G_TYPE_CHECK_INSTANCE_CAST \
1373 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DUE, ECompEditorPropertyPartDue))
1374 #define E_IS_COMP_EDITOR_PROPERTY_PART_DUE(obj) \
1375 	(G_TYPE_CHECK_INSTANCE_TYPE \
1376 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_DUE))
1377 
1378 typedef struct _ECompEditorPropertyPartDue ECompEditorPropertyPartDue;
1379 typedef struct _ECompEditorPropertyPartDueClass ECompEditorPropertyPartDueClass;
1380 
1381 struct _ECompEditorPropertyPartDue {
1382 	ECompEditorPropertyPartDatetimeLabeled parent;
1383 };
1384 
1385 struct _ECompEditorPropertyPartDueClass {
1386 	ECompEditorPropertyPartDatetimeLabeledClass parent_class;
1387 };
1388 
1389 GType e_comp_editor_property_part_due_get_type (void) G_GNUC_CONST;
1390 
G_DEFINE_TYPE(ECompEditorPropertyPartDue,e_comp_editor_property_part_due,E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)1391 G_DEFINE_TYPE (ECompEditorPropertyPartDue, e_comp_editor_property_part_due, E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)
1392 
1393 static void
1394 e_comp_editor_property_part_due_init (ECompEditorPropertyPartDue *part_due)
1395 {
1396 }
1397 
1398 static void
e_comp_editor_property_part_due_class_init(ECompEditorPropertyPartDueClass * klass)1399 e_comp_editor_property_part_due_class_init (ECompEditorPropertyPartDueClass *klass)
1400 {
1401 	ECompEditorPropertyPartDatetimeClass *part_datetime_class;
1402 
1403 	part_datetime_class = E_COMP_EDITOR_PROPERTY_PART_DATETIME_CLASS (klass);
1404 	part_datetime_class->prop_kind = I_CAL_DUE_PROPERTY;
1405 	part_datetime_class->i_cal_new_func = i_cal_property_new_due;
1406 	part_datetime_class->i_cal_set_func = i_cal_property_set_due;
1407 	part_datetime_class->i_cal_get_func = i_cal_property_get_due;
1408 }
1409 
1410 ECompEditorPropertyPart *
e_comp_editor_property_part_due_new(gboolean date_only,gboolean allow_no_date_set)1411 e_comp_editor_property_part_due_new (gboolean date_only,
1412 				     gboolean allow_no_date_set)
1413 {
1414 	ECompEditorPropertyPart *part;
1415 
1416 	part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_DUE,
1417 		"label", C_("ECompEditor", "D_ue date:"),
1418 		NULL);
1419 
1420 	e_comp_editor_property_part_datetime_labeled_setup (
1421 		E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (part),
1422 		date_only, allow_no_date_set);
1423 
1424 	return part;
1425 }
1426 
1427 /* ************************************************************************* */
1428 
1429 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_COMPLETED \
1430 	(e_comp_editor_property_part_completed_get_type ())
1431 #define E_COMP_EDITOR_PROPERTY_PART_COMPLETED(obj) \
1432 	(G_TYPE_CHECK_INSTANCE_CAST \
1433 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_COMPLETED, ECompEditorPropertyPartCompleted))
1434 #define E_IS_COMP_EDITOR_PROPERTY_PART_COMPLETED(obj) \
1435 	(G_TYPE_CHECK_INSTANCE_TYPE \
1436 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_COMPLETED))
1437 
1438 typedef struct _ECompEditorPropertyPartCompleted ECompEditorPropertyPartCompleted;
1439 typedef struct _ECompEditorPropertyPartCompletedClass ECompEditorPropertyPartCompletedClass;
1440 
1441 struct _ECompEditorPropertyPartCompleted {
1442 	ECompEditorPropertyPartDatetimeLabeled parent;
1443 };
1444 
1445 struct _ECompEditorPropertyPartCompletedClass {
1446 	ECompEditorPropertyPartDatetimeLabeledClass parent_class;
1447 };
1448 
1449 GType e_comp_editor_property_part_completed_get_type (void) G_GNUC_CONST;
1450 
G_DEFINE_TYPE(ECompEditorPropertyPartCompleted,e_comp_editor_property_part_completed,E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)1451 G_DEFINE_TYPE (ECompEditorPropertyPartCompleted, e_comp_editor_property_part_completed, E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED)
1452 
1453 static void
1454 e_comp_editor_property_part_completed_ensure_date_time (ICalTime *pvalue)
1455 {
1456 	if (!pvalue)
1457 		return;
1458 
1459 	if (i_cal_time_is_date (pvalue)) {
1460 		i_cal_time_set_is_date (pvalue, FALSE);
1461 		i_cal_time_set_time (pvalue, 0, 0, 0);
1462 		i_cal_time_set_timezone (pvalue, i_cal_timezone_get_utc_timezone ());
1463 	} else if (!i_cal_time_is_utc (pvalue)) {
1464 		/* Make sure the time is in UTC */
1465 		i_cal_time_convert_timezone (pvalue, i_cal_time_get_timezone (pvalue), i_cal_timezone_get_utc_timezone ());
1466 		i_cal_time_set_timezone (pvalue, i_cal_timezone_get_utc_timezone ());
1467 	}
1468 }
1469 
1470 static ICalProperty *
e_comp_editor_property_part_completed_new_func_wrapper(ICalTime * value)1471 e_comp_editor_property_part_completed_new_func_wrapper (ICalTime *value)
1472 {
1473 	e_comp_editor_property_part_completed_ensure_date_time (value);
1474 
1475 	return i_cal_property_new_completed (value);
1476 }
1477 
1478 static void
e_comp_editor_property_part_completed_set_func_wrapper(ICalProperty * prop,ICalTime * value)1479 e_comp_editor_property_part_completed_set_func_wrapper (ICalProperty *prop,
1480 							ICalTime *value)
1481 {
1482 	e_comp_editor_property_part_completed_ensure_date_time (value);
1483 
1484 	i_cal_property_set_completed (prop, value);
1485 }
1486 
1487 static void
e_comp_editor_property_part_completed_init(ECompEditorPropertyPartCompleted * part_completed)1488 e_comp_editor_property_part_completed_init (ECompEditorPropertyPartCompleted *part_completed)
1489 {
1490 }
1491 
1492 static void
e_comp_editor_property_part_completed_class_init(ECompEditorPropertyPartCompletedClass * klass)1493 e_comp_editor_property_part_completed_class_init (ECompEditorPropertyPartCompletedClass *klass)
1494 {
1495 	ECompEditorPropertyPartDatetimeClass *part_datetime_class;
1496 
1497 	part_datetime_class = E_COMP_EDITOR_PROPERTY_PART_DATETIME_CLASS (klass);
1498 	part_datetime_class->prop_kind = I_CAL_COMPLETED_PROPERTY;
1499 	part_datetime_class->i_cal_new_func = e_comp_editor_property_part_completed_new_func_wrapper;
1500 	part_datetime_class->i_cal_set_func = e_comp_editor_property_part_completed_set_func_wrapper;
1501 	part_datetime_class->i_cal_get_func = i_cal_property_get_completed;
1502 }
1503 
1504 ECompEditorPropertyPart *
e_comp_editor_property_part_completed_new(gboolean date_only,gboolean allow_no_date_set)1505 e_comp_editor_property_part_completed_new (gboolean date_only,
1506 					   gboolean allow_no_date_set)
1507 {
1508 	ECompEditorPropertyPart *part;
1509 
1510 	part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_COMPLETED,
1511 		"label", C_("ECompEditor", "Date _completed:"),
1512 		NULL);
1513 
1514 	e_comp_editor_property_part_datetime_labeled_setup (
1515 		E_COMP_EDITOR_PROPERTY_PART_DATETIME_LABELED (part),
1516 		date_only, allow_no_date_set);
1517 
1518 	return part;
1519 }
1520 
1521 /* ************************************************************************* */
1522 
1523 ECompEditorPropertyPart *
e_comp_editor_property_part_classification_new(void)1524 e_comp_editor_property_part_classification_new (void)
1525 {
1526 	ECompEditorPropertyPartPickerMap map[] = {
1527 		{ I_CAL_CLASS_PUBLIC,       NC_("ECompEditor", "Public"),       FALSE, NULL },
1528 		{ I_CAL_CLASS_PRIVATE,      NC_("ECompEditor", "Private"),      FALSE, NULL },
1529 		{ I_CAL_CLASS_CONFIDENTIAL, NC_("ECompEditor", "Confidential"), FALSE, NULL }
1530 	};
1531 	GSettings *settings;
1532 	ECompEditorPropertyPart *part;
1533 	gboolean classify_private;
1534 	gint ii, n_elems = G_N_ELEMENTS (map);
1535 
1536 	for (ii = 0; ii < n_elems; ii++) {
1537 		map[ii].description = g_dpgettext2 (GETTEXT_PACKAGE, "ECompEditor", map[ii].description);
1538 	}
1539 
1540 	settings = e_util_ref_settings ("org.gnome.evolution.calendar");
1541 	classify_private = g_settings_get_boolean (settings, "classify-private");
1542 	g_object_unref (settings);
1543 
1544 	part = e_comp_editor_property_part_picker_with_map_new (map, n_elems,
1545 		C_("ECompEditor", "C_lassification:"),
1546 		I_CAL_CLASS_PROPERTY,
1547 		(ECompEditorPropertyPartPickerMapICalNewFunc) i_cal_property_new_class,
1548 		(ECompEditorPropertyPartPickerMapICalSetFunc) i_cal_property_set_class,
1549 		(ECompEditorPropertyPartPickerMapICalGetFunc) i_cal_property_get_class);
1550 
1551 	e_comp_editor_property_part_picker_with_map_set_selected (
1552 		E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part),
1553 		classify_private ? I_CAL_CLASS_PRIVATE : I_CAL_CLASS_PUBLIC);
1554 
1555 	return part;
1556 }
1557 
1558 /* ************************************************************************* */
1559 
1560 ECompEditorPropertyPart *
e_comp_editor_property_part_status_new(ICalComponentKind kind)1561 e_comp_editor_property_part_status_new (ICalComponentKind kind)
1562 {
1563 	ECompEditorPropertyPartPickerMap map_vevent[] = {
1564 		{ I_CAL_STATUS_NONE,      NULL, TRUE,  NULL },
1565 		{ I_CAL_STATUS_TENTATIVE, NULL, FALSE, NULL },
1566 		{ I_CAL_STATUS_CONFIRMED, NULL, FALSE, NULL },
1567 		{ I_CAL_STATUS_CANCELLED, NULL, FALSE, NULL }
1568 	};
1569 	ECompEditorPropertyPartPickerMap map_vjournal[] = {
1570 		{ I_CAL_STATUS_NONE,      NULL, TRUE,  NULL },
1571 		{ I_CAL_STATUS_DRAFT,     NULL, FALSE, NULL },
1572 		{ I_CAL_STATUS_FINAL,     NULL, FALSE, NULL },
1573 		{ I_CAL_STATUS_CANCELLED, NULL, FALSE, NULL }
1574 	};
1575 	ECompEditorPropertyPartPickerMap map_vtodo[] = {
1576 		{ I_CAL_STATUS_NONE,        NULL, TRUE,  NULL },
1577 		{ I_CAL_STATUS_NEEDSACTION, NULL, FALSE, NULL },
1578 		{ I_CAL_STATUS_INPROCESS,   NULL, FALSE, NULL },
1579 		{ I_CAL_STATUS_COMPLETED,   NULL, FALSE, NULL },
1580 		{ I_CAL_STATUS_CANCELLED,   NULL, FALSE, NULL }
1581 	};
1582 	ECompEditorPropertyPartPickerMap *map;
1583 	gint ii, n_elems;
1584 
1585 	switch (kind) {
1586 	case I_CAL_VEVENT_COMPONENT:
1587 		map = map_vevent;
1588 		n_elems = G_N_ELEMENTS (map_vevent);
1589 		break;
1590 	case I_CAL_VJOURNAL_COMPONENT:
1591 		map = map_vjournal;
1592 		n_elems = G_N_ELEMENTS (map_vjournal);
1593 		break;
1594 	default:
1595 		g_warn_if_reached ();
1596 		/* Falls through */
1597 	case I_CAL_VTODO_COMPONENT:
1598 		map = map_vtodo;
1599 		n_elems = G_N_ELEMENTS (map_vtodo);
1600 		break;
1601 	}
1602 
1603 	for (ii = 0; ii < n_elems; ii++) {
1604 		map[ii].description = cal_comp_util_status_to_localized_string (kind, map[ii].value);
1605 	}
1606 
1607 	return e_comp_editor_property_part_picker_with_map_new (map, n_elems,
1608 		C_("ECompEditor", "_Status:"),
1609 		I_CAL_STATUS_PROPERTY,
1610 		(ECompEditorPropertyPartPickerMapICalNewFunc) i_cal_property_new_status,
1611 		(ECompEditorPropertyPartPickerMapICalSetFunc) i_cal_property_set_status,
1612 		(ECompEditorPropertyPartPickerMapICalGetFunc) i_cal_property_get_status);
1613 }
1614 
1615 /* ************************************************************************* */
1616 
1617 static gboolean
ecepp_priority_matches(gint map_value,gint component_value)1618 ecepp_priority_matches (gint map_value,
1619 			gint component_value)
1620 {
1621 	if (map_value == component_value)
1622 		return TRUE;
1623 
1624 	if (component_value == 0)
1625 		return map_value == 0;
1626 	else if (component_value <= 4)
1627 		return map_value == 3;
1628 	else if (component_value == 5)
1629 		return map_value == 5;
1630 	else
1631 		return map_value == 7;
1632 }
1633 
1634 ECompEditorPropertyPart *
e_comp_editor_property_part_priority_new(void)1635 e_comp_editor_property_part_priority_new (void)
1636 {
1637 	ECompEditorPropertyPartPickerMap map[] = {
1638 		{ 0, NC_("ECompEditor", "Undefined"), TRUE,  ecepp_priority_matches },
1639 		{ 3, NC_("ECompEditor", "High"),      FALSE, ecepp_priority_matches },
1640 		{ 5, NC_("ECompEditor", "Normal"),    FALSE, ecepp_priority_matches },
1641 		{ 7, NC_("ECompEditor", "Low"),       FALSE, ecepp_priority_matches }
1642 	};
1643 	gint ii, n_elems = G_N_ELEMENTS (map);
1644 
1645 	for (ii = 0; ii < n_elems; ii++) {
1646 		map[ii].description = g_dpgettext2 (GETTEXT_PACKAGE, "ECompEditor", map[ii].description);
1647 	}
1648 
1649 	return e_comp_editor_property_part_picker_with_map_new (map, n_elems,
1650 		C_("ECompEditor", "Priorit_y:"),
1651 		I_CAL_PRIORITY_PROPERTY,
1652 		i_cal_property_new_priority,
1653 		i_cal_property_set_priority,
1654 		i_cal_property_get_priority);
1655 }
1656 
1657 /* ************************************************************************* */
1658 
1659 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE \
1660 	(e_comp_editor_property_part_percentcomplete_get_type ())
1661 #define E_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE(obj) \
1662 	(G_TYPE_CHECK_INSTANCE_CAST \
1663 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE, ECompEditorPropertyPartPercentcomplete))
1664 #define E_IS_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE(obj) \
1665 	(G_TYPE_CHECK_INSTANCE_TYPE \
1666 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE))
1667 
1668 typedef struct _ECompEditorPropertyPartPercentcomplete ECompEditorPropertyPartPercentcomplete;
1669 typedef struct _ECompEditorPropertyPartPercentcompleteClass ECompEditorPropertyPartPercentcompleteClass;
1670 
1671 struct _ECompEditorPropertyPartPercentcomplete {
1672 	ECompEditorPropertyPartSpin parent;
1673 };
1674 
1675 struct _ECompEditorPropertyPartPercentcompleteClass {
1676 	ECompEditorPropertyPartSpinClass parent_class;
1677 };
1678 
1679 GType e_comp_editor_property_part_percentcomplete_get_type (void) G_GNUC_CONST;
1680 
G_DEFINE_TYPE(ECompEditorPropertyPartPercentcomplete,e_comp_editor_property_part_percentcomplete,E_TYPE_COMP_EDITOR_PROPERTY_PART_SPIN)1681 G_DEFINE_TYPE (ECompEditorPropertyPartPercentcomplete, e_comp_editor_property_part_percentcomplete, E_TYPE_COMP_EDITOR_PROPERTY_PART_SPIN)
1682 
1683 static void
1684 ecepp_percentcomplete_create_widgets (ECompEditorPropertyPart *property_part,
1685 				      GtkWidget **out_label_widget,
1686 				      GtkWidget **out_edit_widget)
1687 {
1688 	ECompEditorPropertyPartClass *part_class;
1689 
1690 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE (property_part));
1691 	g_return_if_fail (out_label_widget != NULL);
1692 	g_return_if_fail (out_edit_widget != NULL);
1693 
1694 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_percentcomplete_parent_class);
1695 	g_return_if_fail (part_class != NULL);
1696 	g_return_if_fail (part_class->create_widgets != NULL);
1697 
1698 	*out_label_widget = NULL;
1699 
1700 	part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
1701 	g_return_if_fail (*out_label_widget == NULL);
1702 	g_return_if_fail (*out_edit_widget != NULL);
1703 
1704 	*out_label_widget = gtk_label_new_with_mnemonic (C_("ECompEditor", "Percent complete:"));
1705 	gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
1706 
1707 	g_object_set (G_OBJECT (*out_label_widget),
1708 		"hexpand", FALSE,
1709 		"halign", GTK_ALIGN_END,
1710 		"vexpand", FALSE,
1711 		"valign", GTK_ALIGN_CENTER,
1712 		NULL);
1713 
1714 	gtk_widget_show (*out_label_widget);
1715 }
1716 
1717 static void
e_comp_editor_property_part_percentcomplete_init(ECompEditorPropertyPartPercentcomplete * part_percentcomplete)1718 e_comp_editor_property_part_percentcomplete_init (ECompEditorPropertyPartPercentcomplete *part_percentcomplete)
1719 {
1720 }
1721 
1722 static void
e_comp_editor_property_part_percentcomplete_class_init(ECompEditorPropertyPartPercentcompleteClass * klass)1723 e_comp_editor_property_part_percentcomplete_class_init (ECompEditorPropertyPartPercentcompleteClass *klass)
1724 {
1725 	ECompEditorPropertyPartSpinClass *part_spin_class;
1726 	ECompEditorPropertyPartClass *part_class;
1727 
1728 	part_spin_class = E_COMP_EDITOR_PROPERTY_PART_SPIN_CLASS (klass);
1729 	part_spin_class->prop_kind = I_CAL_PERCENTCOMPLETE_PROPERTY;
1730 	part_spin_class->i_cal_new_func = i_cal_property_new_percentcomplete;
1731 	part_spin_class->i_cal_set_func = i_cal_property_set_percentcomplete;
1732 	part_spin_class->i_cal_get_func = i_cal_property_get_percentcomplete;
1733 
1734 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1735 	part_class->create_widgets = ecepp_percentcomplete_create_widgets;
1736 }
1737 
1738 ECompEditorPropertyPart *
e_comp_editor_property_part_percentcomplete_new(void)1739 e_comp_editor_property_part_percentcomplete_new (void)
1740 {
1741 	ECompEditorPropertyPart *part;
1742 
1743 	part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_PERCENTCOMPLETE, NULL);
1744 
1745 	e_comp_editor_property_part_spin_set_range (E_COMP_EDITOR_PROPERTY_PART_SPIN (part), 0, 100);
1746 
1747 	return part;
1748 }
1749 
1750 /* ************************************************************************* */
1751 
1752 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_TIMEZONE \
1753 	(e_comp_editor_property_part_timezone_get_type ())
1754 #define E_COMP_EDITOR_PROPERTY_PART_TIMEZONE(obj) \
1755 	(G_TYPE_CHECK_INSTANCE_CAST \
1756 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_TIMEZONE, ECompEditorPropertyPartTimezone))
1757 #define E_IS_COMP_EDITOR_PROPERTY_PART_TIMEZONE(obj) \
1758 	(G_TYPE_CHECK_INSTANCE_TYPE \
1759 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_TIMEZONE))
1760 
1761 typedef struct _ECompEditorPropertyPartTimezone ECompEditorPropertyPartTimezone;
1762 typedef struct _ECompEditorPropertyPartTimezoneClass ECompEditorPropertyPartTimezoneClass;
1763 
1764 struct _ECompEditorPropertyPartTimezone {
1765 	ECompEditorPropertyPart parent;
1766 };
1767 
1768 struct _ECompEditorPropertyPartTimezoneClass {
1769 	ECompEditorPropertyPartClass parent_class;
1770 };
1771 
1772 GType e_comp_editor_property_part_timezone_get_type (void) G_GNUC_CONST;
1773 
G_DEFINE_TYPE(ECompEditorPropertyPartTimezone,e_comp_editor_property_part_timezone,E_TYPE_COMP_EDITOR_PROPERTY_PART)1774 G_DEFINE_TYPE (ECompEditorPropertyPartTimezone, e_comp_editor_property_part_timezone, E_TYPE_COMP_EDITOR_PROPERTY_PART)
1775 
1776 static void
1777 ecepp_timezone_create_widgets (ECompEditorPropertyPart *property_part,
1778 			       GtkWidget **out_label_widget,
1779 			       GtkWidget **out_edit_widget)
1780 {
1781 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_TIMEZONE (property_part));
1782 	g_return_if_fail (out_label_widget != NULL);
1783 	g_return_if_fail (out_edit_widget != NULL);
1784 
1785 	*out_label_widget = gtk_label_new_with_mnemonic (C_("ECompEditor", "Time _zone:"));
1786 
1787 	g_object_set (G_OBJECT (*out_label_widget),
1788 		"hexpand", FALSE,
1789 		"halign", GTK_ALIGN_END,
1790 		"vexpand", FALSE,
1791 		"valign", GTK_ALIGN_CENTER,
1792 		NULL);
1793 
1794 	gtk_widget_show (*out_label_widget);
1795 
1796 	*out_edit_widget = e_timezone_entry_new ();
1797 	e_timezone_entry_set_allow_none (E_TIMEZONE_ENTRY (*out_edit_widget), TRUE);
1798 	e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (*out_edit_widget), calendar_config_get_icaltimezone ());
1799 
1800 	gtk_widget_show (*out_edit_widget);
1801 
1802 	gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
1803 
1804 	g_signal_connect_swapped (*out_edit_widget, "changed",
1805 		G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
1806 }
1807 
1808 static void
ecepp_timezone_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)1809 ecepp_timezone_fill_widget (ECompEditorPropertyPart *property_part,
1810 			    ICalComponent *component)
1811 {
1812 	/* Nothing to do here, this is sort-of virtual property part */
1813 }
1814 
1815 static void
ecepp_timezone_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)1816 ecepp_timezone_fill_component (ECompEditorPropertyPart *property_part,
1817 			       ICalComponent *component)
1818 {
1819 	/* Nothing to do here, this is sort-of virtual property part */
1820 }
1821 
1822 static void
e_comp_editor_property_part_timezone_init(ECompEditorPropertyPartTimezone * part_timezone)1823 e_comp_editor_property_part_timezone_init (ECompEditorPropertyPartTimezone *part_timezone)
1824 {
1825 }
1826 
1827 static void
e_comp_editor_property_part_timezone_class_init(ECompEditorPropertyPartTimezoneClass * klass)1828 e_comp_editor_property_part_timezone_class_init (ECompEditorPropertyPartTimezoneClass *klass)
1829 {
1830 	ECompEditorPropertyPartClass *part_class;
1831 
1832 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1833 	part_class->create_widgets = ecepp_timezone_create_widgets;
1834 	part_class->fill_widget = ecepp_timezone_fill_widget;
1835 	part_class->fill_component = ecepp_timezone_fill_component;
1836 }
1837 
1838 ECompEditorPropertyPart *
e_comp_editor_property_part_timezone_new(void)1839 e_comp_editor_property_part_timezone_new (void)
1840 {
1841 	return g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_TIMEZONE, NULL);
1842 }
1843 
1844 /* ************************************************************************* */
1845 
1846 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY \
1847 	(e_comp_editor_property_part_transparency_get_type ())
1848 #define E_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY(obj) \
1849 	(G_TYPE_CHECK_INSTANCE_CAST \
1850 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY, ECompEditorPropertyPartTransparency))
1851 #define E_IS_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY(obj) \
1852 	(G_TYPE_CHECK_INSTANCE_TYPE \
1853 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY))
1854 
1855 typedef struct _ECompEditorPropertyPartTransparency ECompEditorPropertyPartTransparency;
1856 typedef struct _ECompEditorPropertyPartTransparencyClass ECompEditorPropertyPartTransparencyClass;
1857 
1858 struct _ECompEditorPropertyPartTransparency {
1859 	ECompEditorPropertyPart parent;
1860 };
1861 
1862 struct _ECompEditorPropertyPartTransparencyClass {
1863 	ECompEditorPropertyPartClass parent_class;
1864 };
1865 
1866 GType e_comp_editor_property_part_transparency_get_type (void) G_GNUC_CONST;
1867 
G_DEFINE_TYPE(ECompEditorPropertyPartTransparency,e_comp_editor_property_part_transparency,E_TYPE_COMP_EDITOR_PROPERTY_PART)1868 G_DEFINE_TYPE (ECompEditorPropertyPartTransparency, e_comp_editor_property_part_transparency, E_TYPE_COMP_EDITOR_PROPERTY_PART)
1869 
1870 static void
1871 ecepp_transparency_create_widgets (ECompEditorPropertyPart *property_part,
1872 				   GtkWidget **out_label_widget,
1873 				   GtkWidget **out_edit_widget)
1874 {
1875 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY (property_part));
1876 	g_return_if_fail (out_label_widget != NULL);
1877 	g_return_if_fail (out_edit_widget != NULL);
1878 
1879 	*out_label_widget = NULL;
1880 
1881 	*out_edit_widget = gtk_check_button_new_with_mnemonic (C_("ECompEditor", "Show time as _busy"));
1882 
1883 	g_object_set (G_OBJECT (*out_edit_widget),
1884 		"hexpand", FALSE,
1885 		"halign", GTK_ALIGN_FILL,
1886 		"vexpand", FALSE,
1887 		"valign", GTK_ALIGN_CENTER,
1888 		NULL);
1889 
1890 	gtk_widget_show (*out_edit_widget);
1891 
1892 	g_signal_connect_swapped (*out_edit_widget, "toggled",
1893 		G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
1894 }
1895 
1896 static void
ecepp_transparency_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)1897 ecepp_transparency_fill_widget (ECompEditorPropertyPart *property_part,
1898 				ICalComponent *component)
1899 {
1900 	GtkWidget *edit_widget;
1901 	ICalProperty *prop;
1902 
1903 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY (property_part));
1904 
1905 	edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1906 	g_return_if_fail (GTK_IS_CHECK_BUTTON (edit_widget));
1907 
1908 	prop = i_cal_component_get_first_property (component, I_CAL_TRANSP_PROPERTY);
1909 	if (prop) {
1910 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (edit_widget),
1911 			i_cal_property_get_transp (prop) == I_CAL_TRANSP_OPAQUE);
1912 
1913 		g_object_unref (prop);
1914 	} else {
1915 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (edit_widget), TRUE);
1916 	}
1917 }
1918 
1919 static void
ecepp_transparency_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)1920 ecepp_transparency_fill_component (ECompEditorPropertyPart *property_part,
1921 				   ICalComponent *component)
1922 {
1923 	GtkWidget *edit_widget;
1924 	ICalProperty *prop;
1925 	ICalPropertyTransp value;
1926 
1927 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY (property_part));
1928 
1929 	edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1930 	g_return_if_fail (GTK_IS_CHECK_BUTTON (edit_widget));
1931 
1932 	value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (edit_widget)) ? I_CAL_TRANSP_OPAQUE : I_CAL_TRANSP_TRANSPARENT;
1933 
1934 	prop = i_cal_component_get_first_property (component, I_CAL_TRANSP_PROPERTY);
1935 	if (prop) {
1936 		i_cal_property_set_transp (prop, value);
1937 	} else {
1938 		prop = i_cal_property_new_transp (value);
1939 		i_cal_component_add_property (component, prop);
1940 	}
1941 
1942 	g_clear_object (&prop);
1943 }
1944 
1945 static void
e_comp_editor_property_part_transparency_init(ECompEditorPropertyPartTransparency * part_transparency)1946 e_comp_editor_property_part_transparency_init (ECompEditorPropertyPartTransparency *part_transparency)
1947 {
1948 }
1949 
1950 static void
e_comp_editor_property_part_transparency_class_init(ECompEditorPropertyPartTransparencyClass * klass)1951 e_comp_editor_property_part_transparency_class_init (ECompEditorPropertyPartTransparencyClass *klass)
1952 {
1953 	ECompEditorPropertyPartClass *part_class;
1954 
1955 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1956 	part_class->create_widgets = ecepp_transparency_create_widgets;
1957 	part_class->fill_widget = ecepp_transparency_fill_widget;
1958 	part_class->fill_component = ecepp_transparency_fill_component;
1959 }
1960 
1961 ECompEditorPropertyPart *
e_comp_editor_property_part_transparency_new(void)1962 e_comp_editor_property_part_transparency_new (void)
1963 {
1964 	return g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_TRANSPARENCY, NULL);
1965 }
1966 
1967 /* ************************************************************************* */
1968 
1969 #define E_TYPE_COMP_EDITOR_PROPERTY_PART_COLOR \
1970 	(e_comp_editor_property_part_color_get_type ())
1971 #define E_COMP_EDITOR_PROPERTY_PART_COLOR(obj) \
1972 	(G_TYPE_CHECK_INSTANCE_CAST \
1973 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_COLOR, ECompEditorPropertyPartColor))
1974 #define E_IS_COMP_EDITOR_PROPERTY_PART_COLOR(obj) \
1975 	(G_TYPE_CHECK_INSTANCE_TYPE \
1976 	((obj), E_TYPE_COMP_EDITOR_PROPERTY_PART_COLOR))
1977 
1978 typedef struct _ECompEditorPropertyPartColor ECompEditorPropertyPartColor;
1979 typedef struct _ECompEditorPropertyPartColorClass ECompEditorPropertyPartColorClass;
1980 
1981 struct _ECompEditorPropertyPartColor {
1982 	ECompEditorPropertyPart parent;
1983 
1984 	gulong notify_current_color_id;
1985 };
1986 
1987 struct _ECompEditorPropertyPartColorClass {
1988 	ECompEditorPropertyPartClass parent_class;
1989 };
1990 
1991 GType e_comp_editor_property_part_color_get_type (void) G_GNUC_CONST;
1992 
G_DEFINE_TYPE(ECompEditorPropertyPartColor,e_comp_editor_property_part_color,E_TYPE_COMP_EDITOR_PROPERTY_PART)1993 G_DEFINE_TYPE (ECompEditorPropertyPartColor, e_comp_editor_property_part_color, E_TYPE_COMP_EDITOR_PROPERTY_PART)
1994 
1995 static const gchar *
1996 ecepp_color_rgba_to_string (const GdkRGBA *rgba)
1997 {
1998 	const struct _colors {
1999 		const gchar *name;
2000 		guchar rr, gg, bb;
2001 	} colors[] = {
2002 		{ "aliceblue",		  240, 248, 255 },
2003 		{ "antiquewhite",	  250, 235, 215 },
2004 		{ "aqua",		    0, 255, 255 },
2005 		{ "aquamarine",		  127, 255, 212 },
2006 		{ "azure",		  240, 255, 255 },
2007 		{ "beige",		  245, 245, 220 },
2008 		{ "bisque",		  255, 228, 196 },
2009 		{ "black",		    0,   0,   0 },
2010 		{ "blanchedalmond",	  255, 235, 205 },
2011 		{ "blue",		    0,   0, 255 },
2012 		{ "blueviolet",		  138,  43, 226 },
2013 		{ "brown",		  165,  42,  42 },
2014 		{ "burlywood",		  222, 184, 135 },
2015 		{ "cadetblue",		   95, 158, 160 },
2016 		{ "chartreuse",		  127, 255,   0 },
2017 		{ "chocolate",		  210, 105,  30 },
2018 		{ "coral",		  255, 127,  80 },
2019 		{ "cornflowerblue",	  100, 149, 237 },
2020 		{ "cornsilk",		  255, 248, 220 },
2021 		{ "crimson",		  220,  20,  60 },
2022 		{ "cyan",		    0, 255, 255 },
2023 		{ "darkblue",		    0,   0, 139 },
2024 		{ "darkcyan",		    0, 139, 139 },
2025 		{ "darkgoldenrod",	  184, 134,  11 },
2026 		{ "darkgray",		  169, 169, 169 },
2027 		{ "darkgreen",		    0, 100,   0 },
2028 		{ "darkgrey",		  169, 169, 169 },
2029 		{ "darkkhaki",		  189, 183, 107 },
2030 		{ "darkmagenta",	  139,   0, 139 },
2031 		{ "darkolivegreen",	   85, 107,  47 },
2032 		{ "darkorange",		  255, 140,   0 },
2033 		{ "darkorchid",		  153,  50, 204 },
2034 		{ "darkred",		  139,   0,   0 },
2035 		{ "darksalmon",		  233, 150, 122 },
2036 		{ "darkseagreen",	  143, 188, 143 },
2037 		{ "darkslateblue",	   72 , 61, 139 },
2038 		{ "darkslategray",	   47,  79,  79 },
2039 		{ "darkslategrey",	   47,  79,  79 },
2040 		{ "darkturquoise",	    0, 206, 209 },
2041 		{ "darkviolet",		  148,   0, 211 },
2042 		{ "deeppink",		  255,  20, 147 },
2043 		{ "deepskyblue",	    0, 191, 255 },
2044 		{ "dimgray",		  105, 105, 105 },
2045 		{ "dimgrey",		  105, 105, 105 },
2046 		{ "dodgerblue",		   30, 144, 255 },
2047 		{ "firebrick",		  178,  34,  34 },
2048 		{ "floralwhite",	  255, 250, 240 },
2049 		{ "forestgreen",	   34, 139,  34 },
2050 		{ "fuchsia",		  255,   0, 255 },
2051 		{ "gainsboro",		  220, 220, 220 },
2052 		{ "ghostwhite",		  248, 248, 255 },
2053 		{ "gold",		  255, 215,   0 },
2054 		{ "goldenrod",		  218, 165,  32 },
2055 		{ "gray",		  128, 128, 128 },
2056 		{ "green",		    0, 128,   0 },
2057 		{ "greenyellow",	  173, 255,  47 },
2058 		{ "grey",		  128, 128, 128 },
2059 		{ "honeydew",		  240, 255, 240 },
2060 		{ "hotpink",		  255, 105, 180 },
2061 		{ "indianred",		  205,  92,  92 },
2062 		{ "indigo",		   75,   0, 130 },
2063 		{ "ivory",		  255, 255, 240 },
2064 		{ "khaki",		  240, 230, 140 },
2065 		{ "lavender",		  230, 230, 250 },
2066 		{ "lavenderblush",	  255, 240, 245 },
2067 		{ "lawngreen",		  124, 252,   0 },
2068 		{ "lemonchiffon",	  255, 250, 205 },
2069 		{ "lightblue",		  173, 216, 230 },
2070 		{ "lightcoral",		  240, 128, 128 },
2071 		{ "lightcyan",		  224, 255, 255 },
2072 		{ "lightgoldenrodyellow", 250, 250, 210 },
2073 		{ "lightgray",		  211, 211, 211 },
2074 		{ "lightgreen",		  144, 238, 144 },
2075 		{ "lightgrey",		  211, 211, 211 },
2076 		{ "lightpink",		  255, 182, 193 },
2077 		{ "lightsalmon",	  255, 160, 122 },
2078 		{ "lightseagreen",	   32, 178, 170 },
2079 		{ "lightskyblue",	  135, 206, 250 },
2080 		{ "lightslategray",	  119, 136, 153 },
2081 		{ "lightslategrey",	  119, 136, 153 },
2082 		{ "lightsteelblue",	  176, 196, 222 },
2083 		{ "lightyellow",	  255, 255, 224 },
2084 		{ "lime",		    0, 255,   0 },
2085 		{ "limegreen",		   50, 205,  50 },
2086 		{ "linen",		  250, 240, 230 },
2087 		{ "magenta",		  255,   0, 255 },
2088 		{ "maroon",		  128,   0,   0 },
2089 		{ "mediumaquamarine",	  102, 205, 170 },
2090 		{ "mediumblue",		    0,   0, 205 },
2091 		{ "mediumorchid",	  186,  85, 211 },
2092 		{ "mediumpurple",	  147, 112, 219 },
2093 		{ "mediumseagreen",	   60, 179, 113 },
2094 		{ "mediumslateblue",	  123, 104, 238 },
2095 		{ "mediumspringgreen",	    0, 250, 154 },
2096 		{ "mediumturquoise",	   72, 209, 204 },
2097 		{ "mediumvioletred",	  199,  21, 133 },
2098 		{ "midnightblue",	   25,  25, 112 },
2099 		{ "mintcream",		  245, 255, 250 },
2100 		{ "mistyrose",		  255, 228, 225 },
2101 		{ "moccasin",		  255, 228, 181 },
2102 		{ "navajowhite",	  255, 222, 173 },
2103 		{ "navy",		    0,   0, 128 },
2104 		{ "oldlace",		  253, 245, 230 },
2105 		{ "olive",		  128, 128,   0 },
2106 		{ "olivedrab",		  107, 142,  35 },
2107 		{ "orange",		  255, 165,   0 },
2108 		{ "orangered",		  255,  69,   0 },
2109 		{ "orchid",		  218, 112, 214 },
2110 		{ "palegoldenrod",	  238, 232, 170 },
2111 		{ "palegreen",		  152, 251, 152 },
2112 		{ "paleturquoise",	  175, 238, 238 },
2113 		{ "palevioletred",	  219, 112, 147 },
2114 		{ "papayawhip",		  255, 239, 213 },
2115 		{ "peachpuff",		  255, 218, 185 },
2116 		{ "peru",		  205, 133, 63  },
2117 		{ "pink",		  255, 192, 203 },
2118 		{ "plum",		  221, 160, 221 },
2119 		{ "powderblue",		  176, 224, 230 },
2120 		{ "purple",		  128,   0, 128 },
2121 		{ "red",		  255,   0,   0 },
2122 		{ "rosybrown",		  188, 143, 143 },
2123 		{ "royalblue",		   65, 105, 225 },
2124 		{ "saddlebrown",	  139,  69,  19 },
2125 		{ "salmon",		  250, 128, 114 },
2126 		{ "sandybrown",		  244, 164,  96 },
2127 		{ "seagreen",		   46, 139,  87 },
2128 		{ "seashell",		  255, 245, 238 },
2129 		{ "sienna",		  160,  82,  45 },
2130 		{ "silver",		  192, 192, 192 },
2131 		{ "skyblue",		  135, 206, 235 },
2132 		{ "slateblue",		  106,  90, 205 },
2133 		{ "slategray",		  112, 128, 144 },
2134 		{ "slategrey",		  112, 128, 144 },
2135 		{ "snow",		  255, 250, 250 },
2136 		{ "springgreen",	    0, 255, 127 },
2137 		{ "steelblue",		   70, 130, 180 },
2138 		{ "tan",		  210, 180, 140 },
2139 		{ "teal",		    0, 128, 128 },
2140 		{ "thistle",		  216, 191, 216 },
2141 		{ "tomato",		  255,  99,  71 },
2142 		{ "turquoise",		   64, 224, 208 },
2143 		{ "violet",		  238, 130, 238 },
2144 		{ "wheat",		  245, 222, 179 },
2145 		{ "white",		  255, 255, 255 },
2146 		{ "whitesmoke",		  245, 245, 245 },
2147 		{ "yellow",		  255, 255,   0 },
2148 		{ "yellowgreen",	  154, 205,  50 }
2149 	};
2150 	guchar rr, gg, bb;
2151 	gint best = G_MAXINT;
2152 	const gchar *name = NULL;
2153 	gint ii;
2154 
2155 	g_return_val_if_fail (rgba != NULL, NULL);
2156 
2157 	rr = 0xFF * rgba->red;
2158 	gg = 0xFF * rgba->green;
2159 	bb = 0xFF * rgba->blue;
2160 
2161 	for (ii = 0; ii < G_N_ELEMENTS (colors); ii++) {
2162 		gint delta_rr, delta_gg, delta_bb, rr_mid;
2163 		gint dist_cc;
2164 
2165 		delta_rr = colors[ii].rr - rr;
2166 		delta_gg = colors[ii].gg - gg;
2167 		delta_bb = colors[ii].bb - bb;
2168 
2169 		/* Exact match */
2170 		if (!delta_rr && !delta_gg && !delta_bb)
2171 			return colors[ii].name;
2172 
2173 		rr_mid = (colors[ii].rr + rr) / 2;
2174 
2175 		/* Euclidean distance: https://en.wikipedia.org/wiki/Color_difference */
2176 		dist_cc = ((2 + (rr_mid / 256.0)) * delta_rr * delta_rr) +
2177 			  (4 * delta_gg * delta_gg) +
2178 			  ((2 + ((255 - rr_mid) / 256.0)) * delta_bb * delta_bb);
2179 
2180 		if (dist_cc < best) {
2181 			best = dist_cc;
2182 			name = colors[ii].name;
2183 		}
2184 	}
2185 
2186 	return name;
2187 }
2188 
2189 static void
ecepp_color_notify_current_color_cb(EColorCombo * color_combo,GParamSpec * param,gpointer user_data)2190 ecepp_color_notify_current_color_cb (EColorCombo *color_combo,
2191 				     GParamSpec *param,
2192 				     gpointer user_data)
2193 {
2194 	ECompEditorPropertyPartColor *color_part = user_data;
2195 	const gchar *color_name;
2196 	GdkRGBA rgba = { 0.0, 0.0, 0.0, 0.0 }, def_rgba = { 0.0, 0.0, 0.0, 0.0 }, parsed = {0.0, 0.0, 0.0, 0.0 };
2197 
2198 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_COLOR (color_part));
2199 
2200 	e_color_combo_get_current_color (color_combo, &rgba);
2201 	e_color_combo_get_default_color (color_combo, &def_rgba);
2202 
2203 	if (gdk_rgba_equal (&rgba, &def_rgba))
2204 		return;
2205 
2206 	color_name = ecepp_color_rgba_to_string (&rgba);
2207 	if (color_name && gdk_rgba_parse (&parsed, color_name) && !gdk_rgba_equal (&rgba, &parsed)) {
2208 		g_signal_handler_block (color_combo, color_part->notify_current_color_id);
2209 		e_color_combo_set_current_color (color_combo, &parsed);
2210 		g_signal_handler_unblock (color_combo, color_part->notify_current_color_id);
2211 	}
2212 }
2213 
2214 static void
ecepp_color_set_palette(GtkWidget * color_combo)2215 ecepp_color_set_palette (GtkWidget *color_combo)
2216 {
2217 	struct _colors {
2218 		const gchar *name;
2219 		GdkRGBA rgba;
2220 	} colors[] = {
2221 		{ "black", { 0, } },
2222 		{ "saddlebrown", { 0, } },
2223 		{ "rosybrown", { 0, } },
2224 		{ "darkgreen", { 0, } },
2225 		{ "midnightblue", { 0, } },
2226 		{ "navy", { 0, } },
2227 		{ "darkslateblue", { 0, } },
2228 		{ "darkslategray", { 0, } },
2229 		{ "maroon", { 0, } },
2230 
2231 		{ "orangered", { 0, } },
2232 		{ "olive", { 0, } },
2233 		{ "green", { 0, } },
2234 		{ "teal", { 0, } },
2235 		{ "blue", { 0, } },
2236 		{ "slategray", { 0, } },
2237 		{ "gray", { 0, } },
2238 		{ "red", { 0, } },
2239 
2240 		{ "orange", { 0, } },
2241 		{ "yellowgreen", { 0, } },
2242 		{ "seagreen", { 0, } },
2243 		{ "mediumturquoise", { 0, } },
2244 		{ "royalblue", { 0, } },
2245 		{ "purple", { 0, } },
2246 		{ "lightslategray", { 0, } },
2247 		{ "fuchsia", { 0, } },
2248 
2249 		{ "gold", { 0, } },
2250 		{ "yellow", { 0, } },
2251 		{ "lime", { 0, } },
2252 		{ "aqua", { 0, } },
2253 		{ "deepskyblue", { 0, } },
2254 		{ "brown", { 0, } },
2255 		{ "silver", { 0, } },
2256 		{ "lightpink", { 0, } },
2257 
2258 		{ "navajowhite", { 0, } },
2259 		{ "khaki", { 0, } },
2260 		{ "beige", { 0, } },
2261 		{ "lightcyan", { 0, } },
2262 		{ "lightskyblue", { 0, } },
2263 		{ "plum", { 0, } },
2264 		{ "white", { 0, } }
2265 	};
2266 	GList *palette = NULL;
2267 	gint ii;
2268 
2269 	g_return_if_fail (E_IS_COLOR_COMBO (color_combo));
2270 
2271 	for (ii = G_N_ELEMENTS (colors) - 1; ii >= 0 ; ii--) {
2272 		g_warn_if_fail (gdk_rgba_parse (&(colors[ii].rgba), colors[ii].name));
2273 
2274 		palette = g_list_prepend (palette, &(colors[ii].rgba));
2275 	}
2276 
2277 	e_color_combo_set_palette (E_COLOR_COMBO (color_combo), palette);
2278 
2279 	g_list_free (palette);
2280 }
2281 
2282 static void
ecepp_color_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)2283 ecepp_color_create_widgets (ECompEditorPropertyPart *property_part,
2284 			    GtkWidget **out_label_widget,
2285 			    GtkWidget **out_edit_widget)
2286 {
2287 	ECompEditorPropertyPartColor *color_part;
2288 	GdkRGBA rgba;
2289 
2290 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_COLOR (property_part));
2291 	g_return_if_fail (out_label_widget != NULL);
2292 	g_return_if_fail (out_edit_widget != NULL);
2293 
2294 	rgba.red = 0.0;
2295 	rgba.green = 0.0;
2296 	rgba.blue = 0.0;
2297 	rgba.alpha = 0.001;
2298 
2299 	*out_label_widget = NULL;
2300 
2301 	/* Translators: This 'None' is meant for 'Color' in calendar component editor, like 'None color' */
2302 	*out_edit_widget = e_color_combo_new_defaults (&rgba, C_("ECompEditor", "None"));
2303 
2304 	g_object_set (G_OBJECT (*out_edit_widget),
2305 		"hexpand", FALSE,
2306 		"halign", GTK_ALIGN_START,
2307 		"vexpand", FALSE,
2308 		"valign", GTK_ALIGN_CENTER,
2309 		NULL);
2310 
2311 	gtk_widget_show (*out_edit_widget);
2312 
2313 	g_signal_connect_swapped (*out_edit_widget, "activated",
2314 		G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
2315 
2316 	ecepp_color_set_palette (*out_edit_widget);
2317 
2318 	color_part = E_COMP_EDITOR_PROPERTY_PART_COLOR (property_part);
2319 	color_part->notify_current_color_id =
2320 		g_signal_connect (*out_edit_widget, "notify::current-color",
2321 		G_CALLBACK (ecepp_color_notify_current_color_cb), property_part);
2322 }
2323 
2324 static void
ecepp_color_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)2325 ecepp_color_fill_widget (ECompEditorPropertyPart *property_part,
2326 			 ICalComponent *component)
2327 {
2328 	GtkWidget *edit_widget;
2329 	ICalProperty *prop;
2330 	gboolean color_set = FALSE;
2331 
2332 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_COLOR (property_part));
2333 
2334 	edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
2335 	g_return_if_fail (E_IS_COLOR_COMBO (edit_widget));
2336 
2337 	prop = i_cal_component_get_first_property (component, I_CAL_COLOR_PROPERTY);
2338 	if (prop) {
2339 		const gchar *color = i_cal_property_get_color (prop);
2340 		GdkRGBA rgba;
2341 
2342 		if (color && gdk_rgba_parse (&rgba, color)) {
2343 			e_color_combo_set_current_color (E_COLOR_COMBO (edit_widget), &rgba);
2344 			color_set = TRUE;
2345 		}
2346 
2347 		g_clear_object (&prop);
2348 	}
2349 
2350 	if (!color_set) {
2351 		GdkRGBA rgba;
2352 
2353 		rgba.red = 0.0;
2354 		rgba.green = 0.0;
2355 		rgba.blue = 0.0;
2356 		rgba.alpha = 0.001;
2357 
2358 		e_color_combo_set_current_color (E_COLOR_COMBO (edit_widget), &rgba);
2359 	}
2360 }
2361 
2362 static void
ecepp_color_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)2363 ecepp_color_fill_component (ECompEditorPropertyPart *property_part,
2364 			    ICalComponent *component)
2365 {
2366 	GtkWidget *edit_widget;
2367 	ICalProperty *prop;
2368 	GdkRGBA rgba;
2369 
2370 	g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_COLOR (property_part));
2371 
2372 	edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
2373 	g_return_if_fail (E_IS_COLOR_COMBO (edit_widget));
2374 
2375 	rgba.red = 0.0;
2376 	rgba.green = 0.0;
2377 	rgba.blue = 0.0;
2378 	rgba.alpha = 0.001;
2379 
2380 	e_color_combo_get_current_color (E_COLOR_COMBO (edit_widget), &rgba);
2381 
2382 	prop = i_cal_component_get_first_property (component, I_CAL_COLOR_PROPERTY);
2383 
2384 	if (rgba.alpha <= 1.0 - 1e-9) {
2385 		if (prop)
2386 			i_cal_component_remove_property (component, prop);
2387 	} else {
2388 		const gchar *str;
2389 
2390 		str = ecepp_color_rgba_to_string (&rgba);
2391 		if (str) {
2392 			if (prop) {
2393 				i_cal_property_set_color (prop, str);
2394 			} else {
2395 				prop = i_cal_property_new_color (str);
2396 				i_cal_component_add_property (component, prop);
2397 			}
2398 		} else {
2399 			g_warning ("%s: Failed to convert RGBA (%f,%f,%f,%f) to string", G_STRFUNC, rgba.red, rgba.green, rgba.blue, rgba.alpha);
2400 		}
2401 	}
2402 
2403 	g_clear_object (&prop);
2404 }
2405 
2406 static void
e_comp_editor_property_part_color_init(ECompEditorPropertyPartColor * part_color)2407 e_comp_editor_property_part_color_init (ECompEditorPropertyPartColor *part_color)
2408 {
2409 }
2410 
2411 static void
e_comp_editor_property_part_color_class_init(ECompEditorPropertyPartColorClass * klass)2412 e_comp_editor_property_part_color_class_init (ECompEditorPropertyPartColorClass *klass)
2413 {
2414 	ECompEditorPropertyPartClass *part_class;
2415 
2416 	part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
2417 	part_class->create_widgets = ecepp_color_create_widgets;
2418 	part_class->fill_widget = ecepp_color_fill_widget;
2419 	part_class->fill_component = ecepp_color_fill_component;
2420 }
2421 
2422 ECompEditorPropertyPart *
e_comp_editor_property_part_color_new(void)2423 e_comp_editor_property_part_color_new (void)
2424 {
2425 	return g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_COLOR, NULL);
2426 }
2427