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, " ") ||
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 (¶m);
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