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 <glib-object.h>
21 #include <gtk/gtk.h>
22
23 #include <e-util/e-util.h>
24
25 #include "calendar-config.h"
26 #include "comp-util.h"
27 #include "e-comp-editor-property-part.h"
28
29 struct _ECompEditorPropertyPartPrivate {
30 GtkWidget *label_widget;
31 GtkWidget *edit_widget;
32 gboolean visible;
33 gboolean sensitize_handled;
34 };
35
36 enum {
37 PROPERTY_PART_PROP_0,
38 PROPERTY_PART_PROP_SENSITIZE_HANDLED,
39 PROPERTY_PART_PROP_VISIBLE
40 };
41
42 enum {
43 PROPERTY_PART_CHANGED,
44 PROPERTY_PART_LAST_SIGNAL
45 };
46
47 static guint property_part_signals[PROPERTY_PART_LAST_SIGNAL];
48
G_DEFINE_ABSTRACT_TYPE(ECompEditorPropertyPart,e_comp_editor_property_part,G_TYPE_OBJECT)49 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPart, e_comp_editor_property_part, G_TYPE_OBJECT)
50
51 static void
52 e_comp_editor_property_part_set_property (GObject *object,
53 guint property_id,
54 const GValue *value,
55 GParamSpec *pspec)
56 {
57 switch (property_id) {
58 case PROPERTY_PART_PROP_SENSITIZE_HANDLED:
59 e_comp_editor_property_part_set_sensitize_handled (
60 E_COMP_EDITOR_PROPERTY_PART (object),
61 g_value_get_boolean (value));
62 return;
63
64 case PROPERTY_PART_PROP_VISIBLE:
65 e_comp_editor_property_part_set_visible (
66 E_COMP_EDITOR_PROPERTY_PART (object),
67 g_value_get_boolean (value));
68 return;
69 }
70
71 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
72 }
73
74 static void
e_comp_editor_property_part_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)75 e_comp_editor_property_part_get_property (GObject *object,
76 guint property_id,
77 GValue *value,
78 GParamSpec *pspec)
79 {
80 switch (property_id) {
81 case PROPERTY_PART_PROP_SENSITIZE_HANDLED:
82 g_value_set_boolean (
83 value,
84 e_comp_editor_property_part_get_sensitize_handled (
85 E_COMP_EDITOR_PROPERTY_PART (object)));
86 return;
87
88 case PROPERTY_PART_PROP_VISIBLE:
89 g_value_set_boolean (
90 value,
91 e_comp_editor_property_part_get_visible (
92 E_COMP_EDITOR_PROPERTY_PART (object)));
93 return;
94 }
95
96 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
97 }
98
99 static void
e_comp_editor_property_part_constructed(GObject * object)100 e_comp_editor_property_part_constructed (GObject *object)
101 {
102 ECompEditorPropertyPart *property_part;
103 GtkWidget *label_widget = NULL, *edit_widget = NULL;
104
105 G_OBJECT_CLASS (e_comp_editor_property_part_parent_class)->constructed (object);
106
107 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (object));
108
109 property_part = E_COMP_EDITOR_PROPERTY_PART (object);
110
111 e_comp_editor_property_part_create_widgets (property_part, &label_widget, &edit_widget);
112
113 if (label_widget) {
114 property_part->priv->label_widget = g_object_ref_sink (label_widget);
115
116 e_binding_bind_property (
117 property_part, "visible",
118 label_widget, "visible",
119 G_BINDING_SYNC_CREATE);
120 }
121
122 if (edit_widget) {
123 property_part->priv->edit_widget = g_object_ref_sink (edit_widget);
124
125 e_binding_bind_property (
126 property_part, "visible",
127 edit_widget, "visible",
128 G_BINDING_SYNC_CREATE);
129 }
130 }
131
132 static void
e_comp_editor_property_part_dispose(GObject * object)133 e_comp_editor_property_part_dispose (GObject *object)
134 {
135 ECompEditorPropertyPart *property_part;
136
137 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (object));
138
139 property_part = E_COMP_EDITOR_PROPERTY_PART (object);
140
141 g_clear_object (&property_part->priv->label_widget);
142 g_clear_object (&property_part->priv->edit_widget);
143
144 G_OBJECT_CLASS (e_comp_editor_property_part_parent_class)->dispose (object);
145 }
146
147 static void
e_comp_editor_property_part_impl_sensitize_widgets(ECompEditorPropertyPart * property_part,gboolean force_insensitive)148 e_comp_editor_property_part_impl_sensitize_widgets (ECompEditorPropertyPart *property_part,
149 gboolean force_insensitive)
150 {
151 GtkWidget *widget;
152
153 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
154
155 widget = e_comp_editor_property_part_get_label_widget (property_part);
156 if (widget)
157 gtk_widget_set_sensitive (widget, !force_insensitive);
158
159 widget = e_comp_editor_property_part_get_edit_widget (property_part);
160 if (widget) {
161 if (GTK_IS_ENTRY (widget))
162 g_object_set (G_OBJECT (widget), "editable", !force_insensitive, NULL);
163 else
164 gtk_widget_set_sensitive (widget, !force_insensitive);
165 }
166 }
167
168 static void
e_comp_editor_property_part_init(ECompEditorPropertyPart * property_part)169 e_comp_editor_property_part_init (ECompEditorPropertyPart *property_part)
170 {
171 property_part->priv = G_TYPE_INSTANCE_GET_PRIVATE (property_part,
172 E_TYPE_COMP_EDITOR_PROPERTY_PART,
173 ECompEditorPropertyPartPrivate);
174 property_part->priv->visible = TRUE;
175 property_part->priv->sensitize_handled = FALSE;
176 }
177
178 static void
e_comp_editor_property_part_class_init(ECompEditorPropertyPartClass * klass)179 e_comp_editor_property_part_class_init (ECompEditorPropertyPartClass *klass)
180 {
181 GObjectClass *object_class;
182
183 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPrivate));
184
185 klass->sensitize_widgets = e_comp_editor_property_part_impl_sensitize_widgets;
186
187 object_class = G_OBJECT_CLASS (klass);
188 object_class->set_property = e_comp_editor_property_part_set_property;
189 object_class->get_property = e_comp_editor_property_part_get_property;
190 object_class->constructed = e_comp_editor_property_part_constructed;
191 object_class->dispose = e_comp_editor_property_part_dispose;
192
193 g_object_class_install_property (
194 object_class,
195 PROPERTY_PART_PROP_VISIBLE,
196 g_param_spec_boolean (
197 "visible",
198 "Visible",
199 "Whether the part is visible",
200 TRUE,
201 G_PARAM_READWRITE |
202 G_PARAM_STATIC_STRINGS));
203
204 g_object_class_install_property (
205 object_class,
206 PROPERTY_PART_PROP_SENSITIZE_HANDLED,
207 g_param_spec_boolean (
208 "sensitize-handled",
209 "Sensitize Handled",
210 "Whether the part's sensitive property is handled by the owner of it",
211 FALSE,
212 G_PARAM_READWRITE |
213 G_PARAM_STATIC_STRINGS));
214
215 property_part_signals[PROPERTY_PART_CHANGED] = g_signal_new (
216 "changed",
217 G_TYPE_FROM_CLASS (klass),
218 G_SIGNAL_RUN_FIRST,
219 G_STRUCT_OFFSET (ECompEditorPropertyPartClass, changed),
220 NULL, NULL, NULL,
221 G_TYPE_NONE, 0,
222 G_TYPE_NONE);
223 }
224
225 gboolean
e_comp_editor_property_part_get_visible(ECompEditorPropertyPart * property_part)226 e_comp_editor_property_part_get_visible (ECompEditorPropertyPart *property_part)
227 {
228 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), FALSE);
229
230 return property_part->priv->visible;
231 }
232
233 void
e_comp_editor_property_part_set_visible(ECompEditorPropertyPart * property_part,gboolean visible)234 e_comp_editor_property_part_set_visible (ECompEditorPropertyPart *property_part,
235 gboolean visible)
236 {
237 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
238
239 if ((property_part->priv->visible ? 1 : 0) == (visible ? 1 : 0))
240 return;
241
242 property_part->priv->visible = visible;
243
244 g_object_notify (G_OBJECT (property_part), "visible");
245 }
246
247 gboolean
e_comp_editor_property_part_get_sensitize_handled(ECompEditorPropertyPart * property_part)248 e_comp_editor_property_part_get_sensitize_handled (ECompEditorPropertyPart *property_part)
249 {
250 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), FALSE);
251
252 return property_part->priv->sensitize_handled;
253 }
254
255 void
e_comp_editor_property_part_set_sensitize_handled(ECompEditorPropertyPart * property_part,gboolean sensitize_handled)256 e_comp_editor_property_part_set_sensitize_handled (ECompEditorPropertyPart *property_part,
257 gboolean sensitize_handled)
258 {
259 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
260
261 if ((property_part->priv->sensitize_handled ? 1 : 0) == (sensitize_handled ? 1 : 0))
262 return;
263
264 property_part->priv->sensitize_handled = sensitize_handled;
265
266 g_object_notify (G_OBJECT (property_part), "sensitize-handled");
267 }
268
269 void
e_comp_editor_property_part_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)270 e_comp_editor_property_part_create_widgets (ECompEditorPropertyPart *property_part,
271 GtkWidget **out_label_widget,
272 GtkWidget **out_edit_widget)
273 {
274 ECompEditorPropertyPartClass *klass;
275
276 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
277
278 g_return_if_fail (property_part->priv->label_widget == NULL);
279 g_return_if_fail (property_part->priv->edit_widget == NULL);
280
281 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
282 g_return_if_fail (klass != NULL);
283 g_return_if_fail (klass->create_widgets != NULL);
284
285 klass->create_widgets (property_part, out_label_widget, out_edit_widget);
286 }
287
288 GtkWidget *
e_comp_editor_property_part_get_label_widget(ECompEditorPropertyPart * property_part)289 e_comp_editor_property_part_get_label_widget (ECompEditorPropertyPart *property_part)
290 {
291 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), NULL);
292
293 return property_part->priv->label_widget;
294 }
295
296 GtkWidget *
e_comp_editor_property_part_get_edit_widget(ECompEditorPropertyPart * property_part)297 e_comp_editor_property_part_get_edit_widget (ECompEditorPropertyPart *property_part)
298 {
299 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), NULL);
300
301 return property_part->priv->edit_widget;
302 }
303
304 void
e_comp_editor_property_part_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)305 e_comp_editor_property_part_fill_widget (ECompEditorPropertyPart *property_part,
306 ICalComponent *component)
307 {
308 ECompEditorPropertyPartClass *klass;
309
310 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
311
312 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
313 g_return_if_fail (klass != NULL);
314 g_return_if_fail (klass->fill_widget != NULL);
315
316 klass->fill_widget (property_part, component);
317 }
318
319 void
e_comp_editor_property_part_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)320 e_comp_editor_property_part_fill_component (ECompEditorPropertyPart *property_part,
321 ICalComponent *component)
322 {
323 ECompEditorPropertyPartClass *klass;
324
325 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
326
327 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
328 g_return_if_fail (klass != NULL);
329 g_return_if_fail (klass->fill_component != NULL);
330
331 klass->fill_component (property_part, component);
332 }
333
334 void
e_comp_editor_property_part_sensitize_widgets(ECompEditorPropertyPart * property_part,gboolean force_insensitive)335 e_comp_editor_property_part_sensitize_widgets (ECompEditorPropertyPart *property_part,
336 gboolean force_insensitive)
337 {
338 ECompEditorPropertyPartClass *klass;
339
340 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
341
342 if (e_comp_editor_property_part_get_sensitize_handled (property_part))
343 return;
344
345 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
346 g_return_if_fail (klass != NULL);
347
348 if (klass->sensitize_widgets)
349 klass->sensitize_widgets (property_part, force_insensitive);
350 }
351
352 void
e_comp_editor_property_part_emit_changed(ECompEditorPropertyPart * property_part)353 e_comp_editor_property_part_emit_changed (ECompEditorPropertyPart *property_part)
354 {
355 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
356
357 g_signal_emit (property_part, property_part_signals[PROPERTY_PART_CHANGED], 0, NULL);
358 }
359
360 /* ************************************************************************* */
361
362 struct _ECompEditorPropertyPartStringPrivate {
363 gboolean is_multivalue;
364 };
365
G_DEFINE_ABSTRACT_TYPE(ECompEditorPropertyPartString,e_comp_editor_property_part_string,E_TYPE_COMP_EDITOR_PROPERTY_PART)366 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartString, e_comp_editor_property_part_string, E_TYPE_COMP_EDITOR_PROPERTY_PART)
367
368 static void
369 ecepp_string_create_widgets (ECompEditorPropertyPart *property_part,
370 GtkWidget **out_label_widget,
371 GtkWidget **out_edit_widget)
372 {
373 ECompEditorPropertyPartStringClass *klass;
374
375 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
376 g_return_if_fail (out_label_widget != NULL);
377 g_return_if_fail (out_edit_widget != NULL);
378
379 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
380 g_return_if_fail (klass != NULL);
381 g_return_if_fail (g_type_is_a (klass->entry_type, GTK_TYPE_ENTRY) ||
382 g_type_is_a (klass->entry_type, GTK_TYPE_TEXT_VIEW));
383
384 /* The descendant sets the 'out_label_widget' parameter */
385 *out_edit_widget = g_object_new (klass->entry_type, NULL);
386 g_return_if_fail (*out_edit_widget != NULL);
387
388 g_object_set (G_OBJECT (*out_edit_widget),
389 "hexpand", FALSE,
390 "halign", GTK_ALIGN_FILL,
391 "vexpand", FALSE,
392 "valign", GTK_ALIGN_START,
393 NULL);
394
395 gtk_widget_show (*out_edit_widget);
396
397 if (g_type_is_a (klass->entry_type, GTK_TYPE_TEXT_VIEW)) {
398 GtkScrolledWindow *scrolled_window;
399 GtkTextBuffer *text_buffer;
400
401 scrolled_window = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
402 gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
403 gtk_scrolled_window_set_shadow_type (scrolled_window, GTK_SHADOW_IN);
404 gtk_widget_show (GTK_WIDGET (scrolled_window));
405
406 gtk_container_add (GTK_CONTAINER (scrolled_window), *out_edit_widget);
407
408 g_object_set (G_OBJECT (*out_edit_widget),
409 "hexpand", TRUE,
410 "halign", GTK_ALIGN_FILL,
411 "vexpand", TRUE,
412 "valign", GTK_ALIGN_FILL,
413 NULL);
414
415 g_object_set (G_OBJECT (scrolled_window),
416 "hexpand", FALSE,
417 "halign", GTK_ALIGN_FILL,
418 "vexpand", FALSE,
419 "valign", GTK_ALIGN_START,
420 NULL);
421
422 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (*out_edit_widget));
423 g_signal_connect_swapped (text_buffer, "changed",
424 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
425
426 *out_edit_widget = GTK_WIDGET (scrolled_window);
427 } else {
428 g_signal_connect_swapped (*out_edit_widget, "changed",
429 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
430 }
431 }
432
433 static void
ecepp_string_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)434 ecepp_string_fill_widget (ECompEditorPropertyPart *property_part,
435 ICalComponent *component)
436 {
437 ECompEditorPropertyPartStringClass *klass;
438 GtkWidget *edit_widget;
439 ICalProperty *prop;
440 gchar *text = NULL;
441
442 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
443 g_return_if_fail (I_CAL_IS_COMPONENT (component));
444
445 edit_widget = e_comp_editor_property_part_string_get_real_edit_widget (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
446 g_return_if_fail (GTK_IS_ENTRY (edit_widget) || GTK_IS_TEXT_VIEW (edit_widget));
447
448 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
449 g_return_if_fail (klass != NULL);
450 g_return_if_fail (klass->prop_kind != I_CAL_NO_PROPERTY);
451 g_return_if_fail (klass->i_cal_get_func != NULL);
452
453 if (e_comp_editor_property_part_string_is_multivalue (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part))) {
454 GString *multivalue = NULL;
455
456 for (prop = i_cal_component_get_first_property (component, klass->prop_kind);
457 prop;
458 g_object_unref (prop), prop = i_cal_component_get_next_property (component, klass->prop_kind)) {
459 const gchar *value;
460
461 value = klass->i_cal_get_func (prop);
462
463 if (!value || !*value)
464 continue;
465
466 if (!multivalue)
467 multivalue = g_string_new ("");
468 else if (multivalue->len)
469 g_string_append_c (multivalue, ',');
470
471 g_string_append (multivalue, value);
472 }
473
474 if (multivalue)
475 text = g_string_free (multivalue, FALSE);
476 } else {
477 prop = i_cal_component_get_first_property (component, klass->prop_kind);
478 if (prop) {
479 text = g_strdup (klass->i_cal_get_func (prop));
480 g_object_unref (prop);
481 }
482 }
483
484 if (GTK_IS_ENTRY (edit_widget)) {
485 gtk_entry_set_text (GTK_ENTRY (edit_widget), text ? text : "");
486 } else /* if (GTK_IS_TEXT_VIEW (edit_widget)) */ {
487 GtkTextBuffer *buffer;
488
489 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit_widget));
490 gtk_text_buffer_set_text (buffer, text ? text : "", -1);
491 }
492
493 e_widget_undo_reset (edit_widget);
494
495 g_free (text);
496 }
497
498 static void
ecepp_string_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)499 ecepp_string_fill_component (ECompEditorPropertyPart *property_part,
500 ICalComponent *component)
501 {
502 ECompEditorPropertyPartStringClass *klass;
503 GtkWidget *edit_widget;
504 ICalProperty *prop;
505 gchar *value;
506
507 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
508 g_return_if_fail (I_CAL_IS_COMPONENT (component));
509
510 edit_widget = e_comp_editor_property_part_string_get_real_edit_widget (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
511 g_return_if_fail (GTK_IS_ENTRY (edit_widget) || GTK_IS_TEXT_VIEW (edit_widget));
512
513 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
514 g_return_if_fail (klass != NULL);
515 g_return_if_fail (klass->prop_kind != I_CAL_NO_PROPERTY);
516 g_return_if_fail (klass->i_cal_new_func != NULL);
517 g_return_if_fail (klass->i_cal_set_func != NULL);
518
519 if (GTK_IS_ENTRY (edit_widget)) {
520 value = g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_widget)));
521 } else /* if (GTK_IS_TEXT_VIEW (edit_widget)) */ {
522 GtkTextBuffer *buffer;
523 GtkTextIter text_iter_start, text_iter_end;
524
525 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit_widget));
526 gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
527 gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
528 value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
529 }
530
531 if (e_comp_editor_property_part_string_is_multivalue (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part))) {
532 /* Clear all multivalues first */
533 e_cal_util_component_remove_property_by_kind (component, klass->prop_kind, TRUE);
534
535 if (value && *value) {
536 gchar **split_value;
537
538 split_value = g_strsplit (value, ",", -1);
539 if (split_value) {
540 gint ii;
541
542 /* Store multivalue properties into multiple properties,
543 to workaround i_cal_component_clone() bug, which escapes
544 commas in such properties. */
545 for (ii = 0; split_value[ii]; ii++) {
546 const gchar *item = split_value[ii];
547
548 if (*item) {
549 prop = klass->i_cal_new_func (item);
550 i_cal_component_take_property (component, prop);
551 }
552 }
553
554 g_strfreev (split_value);
555 }
556 }
557 } else {
558 prop = i_cal_component_get_first_property (component, klass->prop_kind);
559
560 if (value && *value) {
561 if (prop) {
562 klass->i_cal_set_func (prop, value);
563 g_object_unref (prop);
564 } else {
565 prop = klass->i_cal_new_func (value);
566 i_cal_component_take_property (component, prop);
567 }
568 } else if (prop) {
569 i_cal_component_remove_property (component, prop);
570 g_object_unref (prop);
571 }
572 }
573
574 g_free (value);
575 }
576
577 static void
ecepp_string_sensitize_widgets(ECompEditorPropertyPart * property_part,gboolean force_insensitive)578 ecepp_string_sensitize_widgets (ECompEditorPropertyPart *property_part,
579 gboolean force_insensitive)
580 {
581 GtkWidget *widget;
582
583 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
584
585 widget = e_comp_editor_property_part_get_label_widget (property_part);
586 if (widget)
587 gtk_widget_set_sensitive (widget, !force_insensitive);
588
589 widget = e_comp_editor_property_part_string_get_real_edit_widget (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
590 g_return_if_fail (GTK_IS_ENTRY (widget) || GTK_IS_TEXT_VIEW (widget));
591
592 g_object_set (G_OBJECT (widget), "editable", !force_insensitive, NULL);
593 }
594
595 static GtkWidget *
ecepp_string_get_real_edit_widget(ECompEditorPropertyPartString * part_string)596 ecepp_string_get_real_edit_widget (ECompEditorPropertyPartString *part_string)
597 {
598 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string), NULL);
599
600 return e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_string));
601 }
602
603 static void
e_comp_editor_property_part_string_init(ECompEditorPropertyPartString * part_string)604 e_comp_editor_property_part_string_init (ECompEditorPropertyPartString *part_string)
605 {
606 part_string->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_string,
607 E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING,
608 ECompEditorPropertyPartStringPrivate);
609 part_string->priv->is_multivalue = FALSE;
610 }
611
612 static void
e_comp_editor_property_part_string_class_init(ECompEditorPropertyPartStringClass * klass)613 e_comp_editor_property_part_string_class_init (ECompEditorPropertyPartStringClass *klass)
614 {
615 ECompEditorPropertyPartClass *part_class;
616
617 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartStringPrivate));
618
619 klass->entry_type = GTK_TYPE_ENTRY;
620
621 klass->prop_kind = I_CAL_NO_PROPERTY;
622 klass->i_cal_new_func = NULL;
623 klass->i_cal_set_func = NULL;
624 klass->i_cal_get_func = NULL;
625 klass->get_real_edit_widget = ecepp_string_get_real_edit_widget;
626
627 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
628 part_class->create_widgets = ecepp_string_create_widgets;
629 part_class->fill_widget = ecepp_string_fill_widget;
630 part_class->fill_component = ecepp_string_fill_component;
631 part_class->sensitize_widgets = ecepp_string_sensitize_widgets;
632 }
633
634 void
e_comp_editor_property_part_string_attach_focus_tracker(ECompEditorPropertyPartString * part_string,EFocusTracker * focus_tracker)635 e_comp_editor_property_part_string_attach_focus_tracker (ECompEditorPropertyPartString *part_string,
636 EFocusTracker *focus_tracker)
637 {
638 GtkWidget *edit_widget;
639
640 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string));
641
642 if (!focus_tracker)
643 return;
644
645 g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
646
647 edit_widget = e_comp_editor_property_part_string_get_real_edit_widget (part_string);
648
649 if (edit_widget)
650 e_widget_undo_attach (edit_widget, focus_tracker);
651 }
652
653 void
e_comp_editor_property_part_string_set_is_multivalue(ECompEditorPropertyPartString * part_string,gboolean is_multivalue)654 e_comp_editor_property_part_string_set_is_multivalue (ECompEditorPropertyPartString *part_string,
655 gboolean is_multivalue)
656 {
657 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string));
658
659 part_string->priv->is_multivalue = is_multivalue;
660 }
661
662 gboolean
e_comp_editor_property_part_string_is_multivalue(ECompEditorPropertyPartString * part_string)663 e_comp_editor_property_part_string_is_multivalue (ECompEditorPropertyPartString *part_string)
664 {
665 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string), FALSE);
666
667 return part_string->priv->is_multivalue;
668 }
669
670 GtkWidget *
e_comp_editor_property_part_string_get_real_edit_widget(ECompEditorPropertyPartString * part_string)671 e_comp_editor_property_part_string_get_real_edit_widget (ECompEditorPropertyPartString *part_string)
672 {
673 ECompEditorPropertyPartStringClass *klass;
674 GtkWidget *edit_widget;
675
676 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string), NULL);
677
678 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (part_string);
679 g_return_val_if_fail (klass != NULL, NULL);
680 g_return_val_if_fail (klass->get_real_edit_widget != NULL, NULL);
681
682 edit_widget = klass->get_real_edit_widget (part_string);
683
684 if (GTK_IS_SCROLLED_WINDOW (edit_widget))
685 edit_widget = gtk_bin_get_child (GTK_BIN (edit_widget));
686
687 return edit_widget;
688 }
689
690 /* ************************************************************************* */
691
692 struct _ECompEditorPropertyPartDatetimePrivate {
693 GWeakRef timezone_entry;
694 };
695
696 enum {
697 ECEPP_DATETIME_LOOKUP_TIMEZONE,
698 ECEPP_DATETIME_LAST_SIGNAL
699 };
700
701 static guint ecepp_datetime_signals[ECEPP_DATETIME_LAST_SIGNAL];
702
G_DEFINE_ABSTRACT_TYPE(ECompEditorPropertyPartDatetime,e_comp_editor_property_part_datetime,E_TYPE_COMP_EDITOR_PROPERTY_PART)703 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartDatetime, e_comp_editor_property_part_datetime, E_TYPE_COMP_EDITOR_PROPERTY_PART)
704
705 static ICalTimezone *
706 ecepp_datetime_lookup_timezone (ECompEditorPropertyPartDatetime *part_datetime,
707 const gchar *tzid)
708 {
709 ICalTimezone *zone = NULL;
710
711 if (!tzid || !*tzid)
712 return NULL;
713
714 g_signal_emit (part_datetime, ecepp_datetime_signals[ECEPP_DATETIME_LOOKUP_TIMEZONE], 0, tzid, &zone);
715
716 return zone;
717 }
718
719 static struct tm
ecepp_datetime_get_current_time_cb(EDateEdit * date_edit,gpointer user_data)720 ecepp_datetime_get_current_time_cb (EDateEdit *date_edit,
721 gpointer user_data)
722 {
723 GWeakRef *weakref = user_data;
724 ECompEditorPropertyPartDatetime *part_datetime;
725 ICalTime *today = NULL;
726 struct tm tm;
727
728 memset (&tm, 0, sizeof (struct tm));
729
730 g_return_val_if_fail (weakref != NULL, tm);
731
732 part_datetime = g_weak_ref_get (weakref);
733 if (part_datetime) {
734 ETimezoneEntry *timezone_entry = g_weak_ref_get (&part_datetime->priv->timezone_entry);
735 ICalTimezone *editor_zone = NULL;
736
737 if (timezone_entry)
738 editor_zone = e_timezone_entry_get_timezone (timezone_entry);
739
740 if (editor_zone)
741 today = i_cal_time_new_current_with_zone (editor_zone);
742
743 g_clear_object (&timezone_entry);
744 g_object_unref (part_datetime);
745 }
746
747 if (!today)
748 today = i_cal_time_new_current_with_zone (calendar_config_get_icaltimezone ());
749
750 tm = e_cal_util_icaltime_to_tm (today);
751
752 g_clear_object (&today);
753
754 return tm;
755 }
756
757 static void
ecepp_datetime_changed_cb(ECompEditorPropertyPart * property_part)758 ecepp_datetime_changed_cb (ECompEditorPropertyPart *property_part)
759 {
760 GtkWidget *edit_widget;
761
762 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
763
764 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
765
766 if (!edit_widget || e_date_edit_has_focus (E_DATE_EDIT (edit_widget)) ||
767 !e_date_edit_date_is_valid (E_DATE_EDIT (edit_widget)) ||
768 !e_date_edit_time_is_valid (E_DATE_EDIT (edit_widget)))
769 return;
770
771 e_comp_editor_property_part_emit_changed (property_part);
772 }
773
774 static void
ecepp_datetime_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)775 ecepp_datetime_create_widgets (ECompEditorPropertyPart *property_part,
776 GtkWidget **out_label_widget,
777 GtkWidget **out_edit_widget)
778 {
779 ECompEditorPropertyPartDatetimeClass *klass;
780
781 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
782 g_return_if_fail (out_label_widget != NULL);
783 g_return_if_fail (out_edit_widget != NULL);
784
785 klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
786 g_return_if_fail (klass != NULL);
787
788 /* The descendant sets the 'out_label_widget' parameter */
789 *out_edit_widget = e_date_edit_new ();
790 g_return_if_fail (*out_edit_widget != NULL);
791
792 g_object_set (G_OBJECT (*out_edit_widget),
793 "hexpand", FALSE,
794 "halign", GTK_ALIGN_START,
795 "vexpand", FALSE,
796 "valign", GTK_ALIGN_START,
797 NULL);
798
799 gtk_widget_show (*out_edit_widget);
800
801 e_date_edit_set_get_time_callback (E_DATE_EDIT (*out_edit_widget),
802 ecepp_datetime_get_current_time_cb,
803 e_weak_ref_new (property_part), (GDestroyNotify) e_weak_ref_free);
804
805 g_signal_connect_swapped (*out_edit_widget, "changed",
806 G_CALLBACK (ecepp_datetime_changed_cb), property_part);
807 g_signal_connect_swapped (*out_edit_widget, "notify::show-time",
808 G_CALLBACK (ecepp_datetime_changed_cb), property_part);
809 }
810
811 static void
ecepp_datetime_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)812 ecepp_datetime_fill_widget (ECompEditorPropertyPart *property_part,
813 ICalComponent *component)
814 {
815 ECompEditorPropertyPartDatetime *part_datetime;
816 ECompEditorPropertyPartDatetimeClass *klass;
817 GtkWidget *edit_widget;
818 ICalProperty *prop;
819 ICalTime *value = NULL;
820
821 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
822 g_return_if_fail (I_CAL_IS_COMPONENT (component));
823
824 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
825 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
826
827 klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
828 g_return_if_fail (klass != NULL);
829 g_return_if_fail (klass->prop_kind != I_CAL_NO_PROPERTY);
830 g_return_if_fail (klass->i_cal_get_func != NULL);
831
832 part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part);
833
834 prop = i_cal_component_get_first_property (component, klass->prop_kind);
835 if (prop) {
836 ETimezoneEntry *timezone_entry = g_weak_ref_get (&part_datetime->priv->timezone_entry);
837
838 value = klass->i_cal_get_func (prop);
839
840 if (timezone_entry && value && !i_cal_time_is_date (value)) {
841 ICalTimezone *editor_zone = e_timezone_entry_get_timezone (timezone_entry);
842
843 /* Attempt to convert time to the zone used in the editor */
844 if (editor_zone && !i_cal_time_get_timezone (value) && !i_cal_time_is_utc (value)) {
845 ICalParameter *param;
846
847 param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
848 if (param) {
849 const gchar *tzid;
850
851 tzid = i_cal_parameter_get_tzid (param);
852
853 if (tzid && *tzid) {
854 if (editor_zone &&
855 (g_strcmp0 (i_cal_timezone_get_tzid (editor_zone), tzid) == 0 ||
856 g_strcmp0 (i_cal_timezone_get_location (editor_zone), tzid) == 0)) {
857 i_cal_time_set_timezone (value, editor_zone);
858 } else {
859 i_cal_time_set_timezone (value, ecepp_datetime_lookup_timezone (part_datetime, tzid));
860 }
861 }
862
863 g_object_unref (param);
864 }
865 }
866 }
867
868 g_clear_object (&timezone_entry);
869 g_clear_object (&prop);
870 }
871
872 if (!value)
873 value = i_cal_time_new_null_time ();
874
875 e_comp_editor_property_part_datetime_set_value (part_datetime, value);
876
877 g_clear_object (&value);
878 }
879
880 static void
ecepp_datetime_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)881 ecepp_datetime_fill_component (ECompEditorPropertyPart *property_part,
882 ICalComponent *component)
883 {
884 ECompEditorPropertyPartDatetime *part_datetime;
885 ECompEditorPropertyPartDatetimeClass *klass;
886 GtkWidget *edit_widget;
887 EDateEdit *date_edit;
888 ICalProperty *prop;
889 ICalTime *value;
890 time_t tt;
891
892 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
893 g_return_if_fail (I_CAL_IS_COMPONENT (component));
894
895 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
896 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
897
898 klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
899 g_return_if_fail (klass != NULL);
900 g_return_if_fail (klass->prop_kind != I_CAL_NO_PROPERTY);
901 g_return_if_fail (klass->i_cal_new_func != NULL);
902 g_return_if_fail (klass->i_cal_get_func != NULL);
903 g_return_if_fail (klass->i_cal_set_func != NULL);
904
905 part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part);
906 date_edit = E_DATE_EDIT (edit_widget);
907 tt = e_date_edit_get_time (date_edit);
908
909 prop = i_cal_component_get_first_property (component, klass->prop_kind);
910
911 if (e_date_edit_get_allow_no_date_set (date_edit) && tt == (time_t) -1) {
912 if (prop) {
913 i_cal_component_remove_property (component, prop);
914 g_object_unref (prop);
915 }
916 } else {
917 value = e_comp_editor_property_part_datetime_get_value (part_datetime);
918
919 if (prop) {
920 /* Remove the VALUE parameter, to correspond to the actual value being set */
921 i_cal_property_remove_parameter_by_kind (prop, I_CAL_VALUE_PARAMETER);
922
923 klass->i_cal_set_func (prop, value);
924
925 /* Re-read the value, because it could be changed by the descendant */
926 g_clear_object (&value);
927 value = klass->i_cal_get_func (prop);
928
929 cal_comp_util_update_tzid_parameter (prop, value);
930 } else {
931 prop = klass->i_cal_new_func (value);
932
933 /* Re-read the value, because it could be changed by the descendant */
934 g_clear_object (&value);
935 value = klass->i_cal_get_func (prop);
936
937 cal_comp_util_update_tzid_parameter (prop, value);
938 i_cal_component_add_property (component, prop);
939 }
940
941 g_clear_object (&value);
942 g_clear_object (&prop);
943 }
944 }
945
946 static void
ecepp_datetime_finalize(GObject * object)947 ecepp_datetime_finalize (GObject *object)
948 {
949 ECompEditorPropertyPartDatetime *part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (object);
950
951 g_weak_ref_clear (&part_datetime->priv->timezone_entry);
952
953 G_OBJECT_CLASS (e_comp_editor_property_part_datetime_parent_class)->finalize (object);
954 }
955
956 static void
e_comp_editor_property_part_datetime_init(ECompEditorPropertyPartDatetime * part_datetime)957 e_comp_editor_property_part_datetime_init (ECompEditorPropertyPartDatetime *part_datetime)
958 {
959 part_datetime->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_datetime,
960 E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME,
961 ECompEditorPropertyPartDatetimePrivate);
962
963 g_weak_ref_init (&part_datetime->priv->timezone_entry, NULL);
964 }
965
966 static void
e_comp_editor_property_part_datetime_class_init(ECompEditorPropertyPartDatetimeClass * klass)967 e_comp_editor_property_part_datetime_class_init (ECompEditorPropertyPartDatetimeClass *klass)
968 {
969 ECompEditorPropertyPartClass *part_class;
970 GObjectClass *object_class;
971
972 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartDatetimePrivate));
973
974 klass->prop_kind = I_CAL_NO_PROPERTY;
975 klass->i_cal_new_func = NULL;
976 klass->i_cal_set_func = NULL;
977 klass->i_cal_get_func = NULL;
978
979 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
980 part_class->create_widgets = ecepp_datetime_create_widgets;
981 part_class->fill_widget = ecepp_datetime_fill_widget;
982 part_class->fill_component = ecepp_datetime_fill_component;
983
984 object_class = G_OBJECT_CLASS (klass);
985 object_class->finalize = ecepp_datetime_finalize;
986
987 /* ICalTimezone *lookup_timezone (datetime, const gchar *tzid); */
988 ecepp_datetime_signals[ECEPP_DATETIME_LOOKUP_TIMEZONE] = g_signal_new (
989 "lookup-timezone",
990 G_OBJECT_CLASS_TYPE (object_class),
991 G_SIGNAL_ACTION,
992 0,
993 NULL, NULL, NULL,
994 G_TYPE_POINTER, 1,
995 G_TYPE_STRING);
996 }
997
998 void
e_comp_editor_property_part_datetime_attach_timezone_entry(ECompEditorPropertyPartDatetime * part_datetime,ETimezoneEntry * timezone_entry)999 e_comp_editor_property_part_datetime_attach_timezone_entry (ECompEditorPropertyPartDatetime *part_datetime,
1000 ETimezoneEntry *timezone_entry)
1001 {
1002 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
1003 if (timezone_entry)
1004 g_return_if_fail (E_IS_TIMEZONE_ENTRY (timezone_entry));
1005
1006 g_weak_ref_set (&part_datetime->priv->timezone_entry, timezone_entry);
1007 }
1008
1009 void
e_comp_editor_property_part_datetime_set_date_only(ECompEditorPropertyPartDatetime * part_datetime,gboolean date_only)1010 e_comp_editor_property_part_datetime_set_date_only (ECompEditorPropertyPartDatetime *part_datetime,
1011 gboolean date_only)
1012 {
1013 GtkWidget *edit_widget;
1014
1015 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
1016
1017 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1018 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
1019
1020 if ((e_date_edit_get_show_time (E_DATE_EDIT (edit_widget)) ? 1 : 0) == ((!date_only) ? 1 : 0))
1021 return;
1022
1023 e_date_edit_set_show_time (E_DATE_EDIT (edit_widget), !date_only);
1024 }
1025
1026 gboolean
e_comp_editor_property_part_datetime_get_date_only(ECompEditorPropertyPartDatetime * part_datetime)1027 e_comp_editor_property_part_datetime_get_date_only (ECompEditorPropertyPartDatetime *part_datetime)
1028 {
1029 GtkWidget *edit_widget;
1030
1031 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
1032
1033 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1034 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
1035
1036 return !e_date_edit_get_show_time (E_DATE_EDIT (edit_widget));
1037 }
1038
1039 void
e_comp_editor_property_part_datetime_set_allow_no_date_set(ECompEditorPropertyPartDatetime * part_datetime,gboolean allow_no_date_set)1040 e_comp_editor_property_part_datetime_set_allow_no_date_set (ECompEditorPropertyPartDatetime *part_datetime,
1041 gboolean allow_no_date_set)
1042 {
1043 GtkWidget *edit_widget;
1044
1045 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
1046
1047 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1048 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
1049
1050 e_date_edit_set_allow_no_date_set (E_DATE_EDIT (edit_widget), allow_no_date_set);
1051 }
1052
1053 gboolean
e_comp_editor_property_part_datetime_get_allow_no_date_set(ECompEditorPropertyPartDatetime * part_datetime)1054 e_comp_editor_property_part_datetime_get_allow_no_date_set (ECompEditorPropertyPartDatetime *part_datetime)
1055 {
1056 GtkWidget *edit_widget;
1057
1058 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
1059
1060 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1061 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
1062
1063 return !e_date_edit_get_allow_no_date_set (E_DATE_EDIT (edit_widget));
1064 }
1065
1066 void
e_comp_editor_property_part_datetime_set_value(ECompEditorPropertyPartDatetime * part_datetime,const ICalTime * value)1067 e_comp_editor_property_part_datetime_set_value (ECompEditorPropertyPartDatetime *part_datetime,
1068 const ICalTime *value)
1069 {
1070 GtkWidget *edit_widget;
1071 EDateEdit *date_edit;
1072 ICalTime *tmp_value = NULL;
1073
1074 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
1075
1076 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1077 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
1078
1079 date_edit = E_DATE_EDIT (edit_widget);
1080
1081 if (!e_date_edit_get_allow_no_date_set (date_edit) && (!value || i_cal_time_is_null_time (value) ||
1082 !i_cal_time_is_valid_time (value))) {
1083 tmp_value = i_cal_time_new_current_with_zone (i_cal_timezone_get_utc_timezone ());
1084 value = tmp_value;
1085 }
1086
1087 if (!value || i_cal_time_is_null_time (value) ||
1088 !i_cal_time_is_valid_time (value)) {
1089 e_date_edit_set_time (date_edit, (time_t) -1);
1090 } else {
1091 ICalTimezone *zone;
1092
1093 zone = i_cal_time_get_timezone (value);
1094
1095 /* Convert to the same time zone as the editor uses, if different */
1096 if (!i_cal_time_is_date (value) && zone) {
1097 ETimezoneEntry *timezone_entry = g_weak_ref_get (&part_datetime->priv->timezone_entry);
1098
1099 if (timezone_entry) {
1100 ICalTimezone *editor_zone = e_timezone_entry_get_timezone (timezone_entry);
1101
1102 if (editor_zone && zone != editor_zone &&
1103 g_strcmp0 (i_cal_timezone_get_tzid (editor_zone), i_cal_timezone_get_tzid (zone)) != 0 &&
1104 g_strcmp0 (i_cal_timezone_get_location (editor_zone), i_cal_timezone_get_location (zone)) != 0) {
1105 if (tmp_value != value) {
1106 tmp_value = i_cal_time_clone (value);
1107 value = tmp_value;
1108 }
1109
1110 i_cal_time_convert_timezone (tmp_value, zone, editor_zone);
1111 i_cal_time_set_timezone (tmp_value, editor_zone);
1112 }
1113 }
1114
1115 g_clear_object (&timezone_entry);
1116 }
1117
1118 e_date_edit_set_date (date_edit, i_cal_time_get_year (value), i_cal_time_get_month (value), i_cal_time_get_day (value));
1119
1120 if (!i_cal_time_is_date (value))
1121 e_date_edit_set_time_of_day (date_edit, i_cal_time_get_hour (value), i_cal_time_get_minute (value));
1122 else if (e_date_edit_get_show_time (date_edit))
1123 e_date_edit_set_time_of_day (date_edit, 0, 0);
1124 else if (e_date_edit_get_allow_no_date_set (date_edit))
1125 e_date_edit_set_time_of_day (date_edit, -1, -1);
1126
1127 e_comp_editor_property_part_datetime_set_date_only (part_datetime, i_cal_time_is_date (value));
1128 }
1129
1130 g_clear_object (&tmp_value);
1131 }
1132
1133 ICalTime *
e_comp_editor_property_part_datetime_get_value(ECompEditorPropertyPartDatetime * part_datetime)1134 e_comp_editor_property_part_datetime_get_value (ECompEditorPropertyPartDatetime *part_datetime)
1135 {
1136 ETimezoneEntry *timezone_entry = NULL;
1137 GtkWidget *edit_widget;
1138 EDateEdit *date_edit;
1139 ICalTime *value = i_cal_time_new_null_time ();
1140 gint year, month, day;
1141
1142 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), value);
1143
1144 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1145 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), value);
1146
1147 date_edit = E_DATE_EDIT (edit_widget);
1148
1149 if (!e_date_edit_get_date (date_edit, &year, &month, &day))
1150 return value;
1151
1152 i_cal_time_set_date (value, year, month, day);
1153
1154 if (!e_date_edit_get_show_time (date_edit)) {
1155 i_cal_time_set_is_date (value, TRUE);
1156 } else {
1157 gint hour, minute;
1158
1159 i_cal_time_set_timezone (value, NULL);
1160 i_cal_time_set_is_date (value, !e_date_edit_get_time_of_day (date_edit, &hour, &minute));
1161
1162 if (!i_cal_time_is_date (value)) {
1163 i_cal_time_set_time (value, hour, minute, 0);
1164
1165 timezone_entry = g_weak_ref_get (&part_datetime->priv->timezone_entry);
1166 if (timezone_entry) {
1167 ICalTimezone *zone, *utc_zone;
1168
1169 utc_zone = i_cal_timezone_get_utc_timezone ();
1170 zone = e_timezone_entry_get_timezone (timezone_entry);
1171
1172 /* It's required to have set the built-in UTC zone, not its copy,
1173 thus libical knows that it's a UTC time, not a time with UTC TZID. */
1174 if (zone && g_strcmp0 (i_cal_timezone_get_tzid (utc_zone), i_cal_timezone_get_tzid (zone)) == 0)
1175 zone = utc_zone;
1176
1177 i_cal_time_set_timezone (value, zone);
1178 }
1179 }
1180 }
1181
1182 g_clear_object (&timezone_entry);
1183
1184 return value;
1185 }
1186
1187 gboolean
e_comp_editor_property_part_datetime_check_validity(ECompEditorPropertyPartDatetime * part_datetime,gboolean * out_date_is_valid,gboolean * out_time_is_valid)1188 e_comp_editor_property_part_datetime_check_validity (ECompEditorPropertyPartDatetime *part_datetime,
1189 gboolean *out_date_is_valid,
1190 gboolean *out_time_is_valid)
1191 {
1192 GtkWidget *edit_widget;
1193 EDateEdit *date_edit;
1194 gboolean date_is_valid = TRUE, time_is_valid = TRUE;
1195
1196 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
1197
1198 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
1199 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
1200
1201 date_edit = E_DATE_EDIT (edit_widget);
1202
1203 if (!e_date_edit_get_allow_no_date_set (date_edit) ||
1204 e_date_edit_get_time (date_edit) != (time_t) -1) {
1205 date_is_valid = e_date_edit_date_is_valid (date_edit);
1206
1207 if (e_date_edit_get_show_time (date_edit))
1208 time_is_valid = e_date_edit_time_is_valid (date_edit);
1209 }
1210
1211 if (out_date_is_valid)
1212 *out_date_is_valid = date_is_valid;
1213 if (out_time_is_valid)
1214 *out_time_is_valid = time_is_valid;
1215
1216 return date_is_valid && time_is_valid;
1217 }
1218
1219 /* ************************************************************************* */
1220
1221 struct _ECompEditorPropertyPartSpinPrivate {
1222 gint dummy;
1223 };
1224
G_DEFINE_ABSTRACT_TYPE(ECompEditorPropertyPartSpin,e_comp_editor_property_part_spin,E_TYPE_COMP_EDITOR_PROPERTY_PART)1225 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartSpin, e_comp_editor_property_part_spin, E_TYPE_COMP_EDITOR_PROPERTY_PART)
1226
1227 static void
1228 ecepp_spin_create_widgets (ECompEditorPropertyPart *property_part,
1229 GtkWidget **out_label_widget,
1230 GtkWidget **out_edit_widget)
1231 {
1232 ECompEditorPropertyPartSpinClass *klass;
1233
1234 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
1235 g_return_if_fail (out_label_widget != NULL);
1236 g_return_if_fail (out_edit_widget != NULL);
1237
1238 klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
1239 g_return_if_fail (klass != NULL);
1240
1241 /* The descendant sets the 'out_label_widget' parameter */
1242 *out_edit_widget = gtk_spin_button_new_with_range (-10, 10, 1);
1243 g_return_if_fail (*out_edit_widget != NULL);
1244
1245 g_object_set (G_OBJECT (*out_edit_widget),
1246 "hexpand", FALSE,
1247 "halign", GTK_ALIGN_FILL,
1248 "vexpand", FALSE,
1249 "valign", GTK_ALIGN_START,
1250 NULL);
1251
1252 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (*out_edit_widget), 0);
1253
1254 gtk_widget_show (*out_edit_widget);
1255
1256 g_signal_connect_swapped (*out_edit_widget, "value-changed",
1257 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
1258 }
1259
1260 static void
ecepp_spin_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)1261 ecepp_spin_fill_widget (ECompEditorPropertyPart *property_part,
1262 ICalComponent *component)
1263 {
1264 ECompEditorPropertyPartSpinClass *klass;
1265 GtkWidget *edit_widget;
1266 ICalProperty *prop;
1267 gint value;
1268
1269 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
1270 g_return_if_fail (I_CAL_IS_COMPONENT (component));
1271
1272 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1273 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1274
1275 klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
1276 g_return_if_fail (klass != NULL);
1277 g_return_if_fail (klass->prop_kind != I_CAL_NO_PROPERTY);
1278 g_return_if_fail (klass->i_cal_get_func != NULL);
1279
1280 prop = i_cal_component_get_first_property (component, klass->prop_kind);
1281 if (prop) {
1282 value = klass->i_cal_get_func (prop);
1283 g_object_unref (prop);
1284 } else {
1285 gdouble d_min, d_max;
1286
1287 gtk_spin_button_get_range (GTK_SPIN_BUTTON (edit_widget), &d_min, &d_max);
1288
1289 value = (gint) d_min;
1290 }
1291
1292 gtk_spin_button_set_value (GTK_SPIN_BUTTON (edit_widget), value);
1293 }
1294
1295 static void
ecepp_spin_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)1296 ecepp_spin_fill_component (ECompEditorPropertyPart *property_part,
1297 ICalComponent *component)
1298 {
1299 ECompEditorPropertyPartSpinClass *klass;
1300 GtkWidget *edit_widget;
1301 ICalProperty *prop;
1302 gint value;
1303
1304 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
1305 g_return_if_fail (I_CAL_COMPONENT (component));
1306
1307 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1308 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1309
1310 klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
1311 g_return_if_fail (klass != NULL);
1312 g_return_if_fail (klass->prop_kind != I_CAL_NO_PROPERTY);
1313 g_return_if_fail (klass->i_cal_new_func != NULL);
1314 g_return_if_fail (klass->i_cal_set_func != NULL);
1315
1316 value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (edit_widget));
1317 prop = i_cal_component_get_first_property (component, klass->prop_kind);
1318
1319 if (prop) {
1320 klass->i_cal_set_func (prop, value);
1321 } else {
1322 prop = klass->i_cal_new_func (value);
1323 i_cal_component_add_property (component, prop);
1324 }
1325
1326 g_clear_object (&prop);
1327 }
1328
1329 static void
e_comp_editor_property_part_spin_init(ECompEditorPropertyPartSpin * part_spin)1330 e_comp_editor_property_part_spin_init (ECompEditorPropertyPartSpin *part_spin)
1331 {
1332 part_spin->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_spin,
1333 E_TYPE_COMP_EDITOR_PROPERTY_PART_SPIN,
1334 ECompEditorPropertyPartSpinPrivate);
1335 }
1336
1337 static void
e_comp_editor_property_part_spin_class_init(ECompEditorPropertyPartSpinClass * klass)1338 e_comp_editor_property_part_spin_class_init (ECompEditorPropertyPartSpinClass *klass)
1339 {
1340 ECompEditorPropertyPartClass *part_class;
1341
1342 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartSpinPrivate));
1343
1344 klass->prop_kind = I_CAL_NO_PROPERTY;
1345 klass->i_cal_new_func = NULL;
1346 klass->i_cal_set_func = NULL;
1347 klass->i_cal_get_func = NULL;
1348
1349 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1350 part_class->create_widgets = ecepp_spin_create_widgets;
1351 part_class->fill_widget = ecepp_spin_fill_widget;
1352 part_class->fill_component = ecepp_spin_fill_component;
1353 }
1354
1355 void
e_comp_editor_property_part_spin_set_range(ECompEditorPropertyPartSpin * part_spin,gint min_value,gint max_value)1356 e_comp_editor_property_part_spin_set_range (ECompEditorPropertyPartSpin *part_spin,
1357 gint min_value,
1358 gint max_value)
1359 {
1360 GtkWidget *edit_widget;
1361
1362 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (part_spin));
1363
1364 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_spin));
1365 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1366
1367 gtk_spin_button_set_range (GTK_SPIN_BUTTON (edit_widget), min_value, max_value);
1368 }
1369
1370 void
e_comp_editor_property_part_spin_get_range(ECompEditorPropertyPartSpin * part_spin,gint * out_min_value,gint * out_max_value)1371 e_comp_editor_property_part_spin_get_range (ECompEditorPropertyPartSpin *part_spin,
1372 gint *out_min_value,
1373 gint *out_max_value)
1374 {
1375 GtkWidget *edit_widget;
1376 gdouble d_min = 0, d_max = 0;
1377
1378 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (part_spin));
1379
1380 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_spin));
1381 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1382
1383 gtk_spin_button_get_range (GTK_SPIN_BUTTON (edit_widget), &d_min, &d_max);
1384
1385 if (out_min_value)
1386 *out_min_value = (gint) d_min;
1387 if (out_max_value)
1388 *out_max_value = (gint) d_max;
1389 }
1390
1391 /* ************************************************************************* */
1392
1393 struct _ECompEditorPropertyPartPickerPrivate {
1394 gint dummy;
1395 };
1396
G_DEFINE_ABSTRACT_TYPE(ECompEditorPropertyPartPicker,e_comp_editor_property_part_picker,E_TYPE_COMP_EDITOR_PROPERTY_PART)1397 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartPicker, e_comp_editor_property_part_picker, E_TYPE_COMP_EDITOR_PROPERTY_PART)
1398
1399 static void
1400 ecepp_picker_create_widgets (ECompEditorPropertyPart *property_part,
1401 GtkWidget **out_label_widget,
1402 GtkWidget **out_edit_widget)
1403 {
1404 ECompEditorPropertyPartPickerClass *klass;
1405 GtkComboBoxText *combo_box;
1406 GSList *ids = NULL, *display_names = NULL, *i_link, *dn_link;
1407
1408 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
1409 g_return_if_fail (out_label_widget != NULL);
1410 g_return_if_fail (out_edit_widget != NULL);
1411
1412 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (property_part);
1413 g_return_if_fail (klass != NULL);
1414
1415 /* The descendant sets the 'out_label_widget' parameter */
1416 *out_edit_widget = gtk_combo_box_text_new ();
1417 g_return_if_fail (*out_edit_widget != NULL);
1418
1419 g_object_set (G_OBJECT (*out_edit_widget),
1420 "hexpand", FALSE,
1421 "halign", GTK_ALIGN_FILL,
1422 "vexpand", FALSE,
1423 "valign", GTK_ALIGN_START,
1424 NULL);
1425
1426 gtk_widget_show (*out_edit_widget);
1427
1428 e_comp_editor_property_part_picker_get_values (E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
1429 &ids, &display_names);
1430
1431 g_warn_if_fail (g_slist_length (ids) == g_slist_length (display_names));
1432
1433 combo_box = GTK_COMBO_BOX_TEXT (*out_edit_widget);
1434
1435 for (i_link = ids, dn_link = display_names; i_link && dn_link; i_link = g_slist_next (i_link), dn_link = g_slist_next (dn_link)) {
1436 const gchar *id, *display_name;
1437
1438 id = i_link->data;
1439 display_name = dn_link->data;
1440
1441 g_warn_if_fail (id != NULL);
1442 g_warn_if_fail (display_name != NULL);
1443
1444 if (!id || !display_name)
1445 continue;
1446
1447 gtk_combo_box_text_append (combo_box, id, display_name);
1448 }
1449
1450 g_slist_free_full (ids, g_free);
1451 g_slist_free_full (display_names, g_free);
1452
1453 g_signal_connect_swapped (*out_edit_widget, "changed",
1454 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
1455 }
1456
1457 static void
ecepp_picker_fill_widget(ECompEditorPropertyPart * property_part,ICalComponent * component)1458 ecepp_picker_fill_widget (ECompEditorPropertyPart *property_part,
1459 ICalComponent *component)
1460 {
1461 GtkWidget *edit_widget;
1462 gchar *id = NULL;
1463
1464 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
1465 g_return_if_fail (I_CAL_IS_COMPONENT (component));
1466
1467 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1468 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
1469
1470 if (e_comp_editor_property_part_picker_get_from_component (
1471 E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
1472 component, &id) && id) {
1473 gtk_combo_box_set_active_id (GTK_COMBO_BOX (edit_widget), id);
1474 g_free (id);
1475 } else {
1476 gtk_combo_box_set_active (GTK_COMBO_BOX (edit_widget), 0);
1477 }
1478 }
1479
1480 static void
ecepp_picker_fill_component(ECompEditorPropertyPart * property_part,ICalComponent * component)1481 ecepp_picker_fill_component (ECompEditorPropertyPart *property_part,
1482 ICalComponent *component)
1483 {
1484 GtkWidget *edit_widget;
1485 const gchar *id;
1486
1487 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
1488 g_return_if_fail (I_CAL_IS_COMPONENT (component));
1489
1490 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1491 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
1492
1493 id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (edit_widget));
1494 if (id) {
1495 e_comp_editor_property_part_picker_set_to_component (
1496 E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
1497 id, component);
1498 }
1499 }
1500
1501 static void
e_comp_editor_property_part_picker_init(ECompEditorPropertyPartPicker * part_picker)1502 e_comp_editor_property_part_picker_init (ECompEditorPropertyPartPicker *part_picker)
1503 {
1504 part_picker->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_picker,
1505 E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER,
1506 ECompEditorPropertyPartPickerPrivate);
1507 }
1508
1509 static void
e_comp_editor_property_part_picker_class_init(ECompEditorPropertyPartPickerClass * klass)1510 e_comp_editor_property_part_picker_class_init (ECompEditorPropertyPartPickerClass *klass)
1511 {
1512 ECompEditorPropertyPartClass *part_class;
1513
1514 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPickerPrivate));
1515
1516 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1517 part_class->create_widgets = ecepp_picker_create_widgets;
1518 part_class->fill_widget = ecepp_picker_fill_widget;
1519 part_class->fill_component = ecepp_picker_fill_component;
1520 }
1521
1522 /* Both out_ids and out_display_names contain newly allocated strings,
1523 where also n-th element of out_uids corresponds to n-th element of
1524 the out_display_names. */
1525 void
e_comp_editor_property_part_picker_get_values(ECompEditorPropertyPartPicker * part_picker,GSList ** out_ids,GSList ** out_display_names)1526 e_comp_editor_property_part_picker_get_values (ECompEditorPropertyPartPicker *part_picker,
1527 GSList **out_ids,
1528 GSList **out_display_names)
1529 {
1530 ECompEditorPropertyPartPickerClass *klass;
1531
1532 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
1533
1534 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
1535 g_return_if_fail (klass != NULL);
1536 g_return_if_fail (klass->get_values != NULL);
1537
1538 klass->get_values (part_picker, out_ids, out_display_names);
1539 }
1540
1541 gboolean
e_comp_editor_property_part_picker_get_from_component(ECompEditorPropertyPartPicker * part_picker,ICalComponent * component,gchar ** out_id)1542 e_comp_editor_property_part_picker_get_from_component (ECompEditorPropertyPartPicker *part_picker,
1543 ICalComponent *component,
1544 gchar **out_id)
1545 {
1546 ECompEditorPropertyPartPickerClass *klass;
1547
1548 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker), FALSE);
1549
1550 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
1551 g_return_val_if_fail (klass != NULL, FALSE);
1552 g_return_val_if_fail (klass->get_from_component != NULL, FALSE);
1553
1554 return klass->get_from_component (part_picker, component, out_id);
1555 }
1556
1557 void
e_comp_editor_property_part_picker_set_to_component(ECompEditorPropertyPartPicker * part_picker,const gchar * id,ICalComponent * component)1558 e_comp_editor_property_part_picker_set_to_component (ECompEditorPropertyPartPicker *part_picker,
1559 const gchar *id,
1560 ICalComponent *component)
1561 {
1562 ECompEditorPropertyPartPickerClass *klass;
1563
1564 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
1565
1566 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
1567 g_return_if_fail (klass != NULL);
1568 g_return_if_fail (klass->set_to_component != NULL);
1569
1570 klass->set_to_component (part_picker, id, component);
1571 }
1572
1573 const gchar *
e_comp_editor_property_part_picker_get_selected_id(ECompEditorPropertyPartPicker * part_picker)1574 e_comp_editor_property_part_picker_get_selected_id (ECompEditorPropertyPartPicker *part_picker)
1575 {
1576 GtkWidget *edit_widget;
1577
1578 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker), NULL);
1579
1580 edit_widget = e_comp_editor_property_part_get_edit_widget (
1581 E_COMP_EDITOR_PROPERTY_PART (part_picker));
1582 g_return_val_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget), NULL);
1583
1584 return gtk_combo_box_get_active_id (GTK_COMBO_BOX (edit_widget));
1585 }
1586
1587 void
e_comp_editor_property_part_picker_set_selected_id(ECompEditorPropertyPartPicker * part_picker,const gchar * id)1588 e_comp_editor_property_part_picker_set_selected_id (ECompEditorPropertyPartPicker *part_picker,
1589 const gchar *id)
1590 {
1591 GtkWidget *edit_widget;
1592
1593 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
1594 g_return_if_fail (id != NULL);
1595
1596 edit_widget = e_comp_editor_property_part_get_edit_widget (
1597 E_COMP_EDITOR_PROPERTY_PART (part_picker));
1598 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
1599
1600 gtk_combo_box_set_active_id (GTK_COMBO_BOX (edit_widget), id);
1601 }
1602
1603 /* ************************************************************************* */
1604
1605 struct _ECompEditorPropertyPartPickerWithMapPrivate {
1606 ECompEditorPropertyPartPickerMap *map;
1607 gint n_map_elems;
1608 gchar *label;
1609
1610 ICalPropertyKind prop_kind;
1611 ECompEditorPropertyPartPickerMapICalNewFunc i_cal_new_func;
1612 ECompEditorPropertyPartPickerMapICalSetFunc i_cal_set_func;
1613 ECompEditorPropertyPartPickerMapICalGetFunc i_cal_get_func;
1614 };
1615
1616 enum {
1617 PICKER_WITH_MAP_PROP_0,
1618 PICKER_WITH_MAP_PROP_MAP,
1619 PICKER_WITH_MAP_PROP_LABEL
1620 };
1621
G_DEFINE_TYPE(ECompEditorPropertyPartPickerWithMap,e_comp_editor_property_part_picker_with_map,E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER)1622 G_DEFINE_TYPE (ECompEditorPropertyPartPickerWithMap, e_comp_editor_property_part_picker_with_map, E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER)
1623
1624 static void
1625 ecepp_picker_with_map_get_values (ECompEditorPropertyPartPicker *part_picker,
1626 GSList **out_ids,
1627 GSList **out_display_names)
1628 {
1629 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1630 gint ii;
1631
1632 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker));
1633 g_return_if_fail (out_ids != NULL);
1634 g_return_if_fail (out_display_names != NULL);
1635
1636 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
1637 g_return_if_fail (part_picker_with_map->priv->map != NULL);
1638 g_return_if_fail (part_picker_with_map->priv->n_map_elems > 0);
1639
1640 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1641 *out_ids = g_slist_prepend (*out_ids, g_strdup_printf ("%d", ii));
1642 *out_display_names = g_slist_prepend (*out_display_names,
1643 g_strdup (part_picker_with_map->priv->map[ii].description));
1644 }
1645
1646 *out_ids = g_slist_reverse (*out_ids);
1647 *out_display_names = g_slist_reverse (*out_display_names);
1648 }
1649
1650 static gboolean
ecepp_picker_with_map_get_from_component(ECompEditorPropertyPartPicker * part_picker,ICalComponent * component,gchar ** out_id)1651 ecepp_picker_with_map_get_from_component (ECompEditorPropertyPartPicker *part_picker,
1652 ICalComponent *component,
1653 gchar **out_id)
1654 {
1655 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1656 ICalProperty *prop;
1657 gint ii, value;
1658
1659 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker), FALSE);
1660 g_return_val_if_fail (I_CAL_IS_COMPONENT (component), FALSE);
1661 g_return_val_if_fail (out_id != NULL, FALSE);
1662
1663 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
1664 g_return_val_if_fail (part_picker_with_map->priv->map != NULL, FALSE);
1665 g_return_val_if_fail (part_picker_with_map->priv->n_map_elems > 0, FALSE);
1666 g_return_val_if_fail (part_picker_with_map->priv->prop_kind != I_CAL_NO_PROPERTY, FALSE);
1667 g_return_val_if_fail (part_picker_with_map->priv->i_cal_get_func != NULL, FALSE);
1668
1669 prop = i_cal_component_get_first_property (component, part_picker_with_map->priv->prop_kind);
1670 if (!prop)
1671 return FALSE;
1672
1673 value = part_picker_with_map->priv->i_cal_get_func (prop);
1674 g_clear_object (&prop);
1675
1676 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1677 gboolean matches;
1678
1679 if (part_picker_with_map->priv->map[ii].matches_func) {
1680 matches = part_picker_with_map->priv->map[ii].matches_func (part_picker_with_map->priv->map[ii].value, value);
1681 } else {
1682 matches = value == part_picker_with_map->priv->map[ii].value;
1683 }
1684
1685 if (matches) {
1686 *out_id = g_strdup_printf ("%d", ii);
1687 return TRUE;
1688 }
1689 }
1690
1691 return FALSE;
1692 }
1693
1694 static void
ecepp_picker_with_map_set_to_component(ECompEditorPropertyPartPicker * part_picker,const gchar * id,ICalComponent * component)1695 ecepp_picker_with_map_set_to_component (ECompEditorPropertyPartPicker *part_picker,
1696 const gchar *id,
1697 ICalComponent *component)
1698 {
1699 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1700 ICalProperty *prop;
1701 gint ii, value;
1702
1703 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker));
1704 g_return_if_fail (id != NULL);
1705 g_return_if_fail (I_CAL_IS_COMPONENT (component));
1706
1707 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
1708 g_return_if_fail (part_picker_with_map->priv->map != NULL);
1709 g_return_if_fail (part_picker_with_map->priv->n_map_elems > 0);
1710 g_return_if_fail (part_picker_with_map->priv->prop_kind != I_CAL_NO_PROPERTY);
1711 g_return_if_fail (part_picker_with_map->priv->i_cal_new_func != NULL);
1712 g_return_if_fail (part_picker_with_map->priv->i_cal_set_func != NULL);
1713
1714 ii = (gint) g_ascii_strtoll (id, NULL, 10);
1715 g_return_if_fail (ii >= 0 && ii < part_picker_with_map->priv->n_map_elems);
1716
1717 prop = i_cal_component_get_first_property (component, part_picker_with_map->priv->prop_kind);
1718 value = part_picker_with_map->priv->map[ii].value;
1719
1720 if (part_picker_with_map->priv->map[ii].delete_prop) {
1721 if (prop)
1722 i_cal_component_remove_property (component, prop);
1723 } else if (prop) {
1724 part_picker_with_map->priv->i_cal_set_func (prop, value);
1725 } else {
1726 prop = part_picker_with_map->priv->i_cal_new_func (value);
1727 i_cal_component_add_property (component, prop);
1728 }
1729
1730 g_clear_object (&prop);
1731 }
1732
1733 static void
ecepp_picker_with_map_create_widgets(ECompEditorPropertyPart * property_part,GtkWidget ** out_label_widget,GtkWidget ** out_edit_widget)1734 ecepp_picker_with_map_create_widgets (ECompEditorPropertyPart *property_part,
1735 GtkWidget **out_label_widget,
1736 GtkWidget **out_edit_widget)
1737 {
1738 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1739 ECompEditorPropertyPartClass *part_class;
1740
1741 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part));
1742 g_return_if_fail (out_label_widget != NULL);
1743 g_return_if_fail (out_edit_widget != NULL);
1744
1745 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_picker_with_map_parent_class);
1746 g_return_if_fail (part_class != NULL);
1747 g_return_if_fail (part_class->create_widgets != NULL);
1748
1749 *out_label_widget = NULL;
1750
1751 part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
1752 g_return_if_fail (*out_label_widget == NULL);
1753 g_return_if_fail (*out_edit_widget != NULL);
1754
1755 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part);
1756
1757 *out_label_widget = gtk_label_new_with_mnemonic (part_picker_with_map->priv->label);
1758 gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
1759
1760 g_object_set (G_OBJECT (*out_label_widget),
1761 "hexpand", FALSE,
1762 "halign", GTK_ALIGN_END,
1763 "vexpand", FALSE,
1764 "valign", GTK_ALIGN_CENTER,
1765 NULL);
1766
1767 gtk_widget_show (*out_label_widget);
1768 }
1769
1770 static void
ecepp_picker_with_map_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)1771 ecepp_picker_with_map_set_property (GObject *object,
1772 guint property_id,
1773 const GValue *value,
1774 GParamSpec *pspec)
1775 {
1776 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1777 gint ii;
1778
1779 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object));
1780
1781 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object);
1782
1783 switch (property_id) {
1784 case PICKER_WITH_MAP_PROP_MAP:
1785 g_return_if_fail (part_picker_with_map->priv->map == NULL);
1786
1787 part_picker_with_map->priv->map = g_value_get_pointer (value);
1788 for (ii = 0; part_picker_with_map->priv->map[ii].description; ii++) {
1789 /* pre-count elements */
1790 }
1791
1792 part_picker_with_map->priv->n_map_elems = ii;
1793 return;
1794
1795 case PICKER_WITH_MAP_PROP_LABEL:
1796 g_free (part_picker_with_map->priv->label);
1797 part_picker_with_map->priv->label = g_value_dup_string (value);
1798 return;
1799 }
1800
1801 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1802 }
1803
1804 static void
ecepp_picker_with_map_finalize(GObject * object)1805 ecepp_picker_with_map_finalize (GObject *object)
1806 {
1807 ECompEditorPropertyPartPickerWithMap *part_picker_with_map =
1808 E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object);
1809
1810 if (part_picker_with_map->priv->map && part_picker_with_map->priv->n_map_elems > 0) {
1811 gint ii;
1812
1813 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1814 g_free ((gchar *) part_picker_with_map->priv->map[ii].description);
1815 }
1816
1817 g_free (part_picker_with_map->priv->map);
1818 part_picker_with_map->priv->map = NULL;
1819 }
1820
1821 g_free (part_picker_with_map->priv->label);
1822 part_picker_with_map->priv->label = NULL;
1823
1824 G_OBJECT_CLASS (e_comp_editor_property_part_picker_with_map_parent_class)->finalize (object);
1825 }
1826
1827 static void
e_comp_editor_property_part_picker_with_map_init(ECompEditorPropertyPartPickerWithMap * part_picker_with_map)1828 e_comp_editor_property_part_picker_with_map_init (ECompEditorPropertyPartPickerWithMap *part_picker_with_map)
1829 {
1830 part_picker_with_map->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_picker_with_map,
1831 E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP,
1832 ECompEditorPropertyPartPickerWithMapPrivate);
1833 }
1834
1835 static void
e_comp_editor_property_part_picker_with_map_class_init(ECompEditorPropertyPartPickerWithMapClass * klass)1836 e_comp_editor_property_part_picker_with_map_class_init (ECompEditorPropertyPartPickerWithMapClass *klass)
1837 {
1838 ECompEditorPropertyPartPickerClass *part_picker_class;
1839 ECompEditorPropertyPartClass *part_class;
1840 GObjectClass *object_class;
1841
1842 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPickerWithMapPrivate));
1843
1844 part_picker_class = E_COMP_EDITOR_PROPERTY_PART_PICKER_CLASS (klass);
1845 part_picker_class->get_values = ecepp_picker_with_map_get_values;
1846 part_picker_class->get_from_component = ecepp_picker_with_map_get_from_component;
1847 part_picker_class->set_to_component = ecepp_picker_with_map_set_to_component;
1848
1849 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1850 part_class->create_widgets = ecepp_picker_with_map_create_widgets;
1851
1852 object_class = G_OBJECT_CLASS (klass);
1853 object_class->set_property = ecepp_picker_with_map_set_property;
1854 object_class->finalize = ecepp_picker_with_map_finalize;
1855
1856 g_object_class_install_property (
1857 object_class,
1858 PICKER_WITH_MAP_PROP_MAP,
1859 g_param_spec_pointer (
1860 "map",
1861 "Map",
1862 "Map of values, .description-NULL-terminated",
1863 G_PARAM_WRITABLE |
1864 G_PARAM_CONSTRUCT_ONLY |
1865 G_PARAM_STATIC_STRINGS));
1866
1867 g_object_class_install_property (
1868 object_class,
1869 PICKER_WITH_MAP_PROP_LABEL,
1870 g_param_spec_string (
1871 "label",
1872 "Label",
1873 "Label of the picker",
1874 NULL,
1875 G_PARAM_WRITABLE |
1876 G_PARAM_CONSTRUCT_ONLY |
1877 G_PARAM_STATIC_STRINGS));
1878 }
1879
1880 ECompEditorPropertyPart *
e_comp_editor_property_part_picker_with_map_new(const ECompEditorPropertyPartPickerMap map[],gint n_map_elements,const gchar * label,ICalPropertyKind prop_kind,ECompEditorPropertyPartPickerMapICalNewFunc i_cal_new_func,ECompEditorPropertyPartPickerMapICalSetFunc i_cal_set_func,ECompEditorPropertyPartPickerMapICalGetFunc i_cal_get_func)1881 e_comp_editor_property_part_picker_with_map_new (const ECompEditorPropertyPartPickerMap map[],
1882 gint n_map_elements,
1883 const gchar *label,
1884 ICalPropertyKind prop_kind,
1885 ECompEditorPropertyPartPickerMapICalNewFunc i_cal_new_func,
1886 ECompEditorPropertyPartPickerMapICalSetFunc i_cal_set_func,
1887 ECompEditorPropertyPartPickerMapICalGetFunc i_cal_get_func)
1888 {
1889 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1890 ECompEditorPropertyPartPickerMap *map_copy;
1891 ECompEditorPropertyPart *property_part;
1892 gint ii;
1893
1894 g_return_val_if_fail (map != NULL, NULL);
1895 g_return_val_if_fail (n_map_elements > 0, NULL);
1896 g_return_val_if_fail (label != NULL, NULL);
1897 g_return_val_if_fail (prop_kind != I_CAL_NO_PROPERTY, NULL);
1898 g_return_val_if_fail (i_cal_new_func != NULL, NULL);
1899 g_return_val_if_fail (i_cal_set_func != NULL, NULL);
1900 g_return_val_if_fail (i_cal_get_func != NULL, NULL);
1901
1902 map_copy = g_new0 (ECompEditorPropertyPartPickerMap, n_map_elements + 1);
1903 for (ii = 0; ii < n_map_elements; ii++) {
1904 map_copy[ii] = map[ii];
1905 map_copy[ii].description = g_strdup (map[ii].description);
1906 }
1907
1908 property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP,
1909 "map", map_copy,
1910 "label", label,
1911 NULL);
1912
1913 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part);
1914
1915 part_picker_with_map->priv->prop_kind = prop_kind;
1916 part_picker_with_map->priv->i_cal_new_func = i_cal_new_func;
1917 part_picker_with_map->priv->i_cal_set_func = i_cal_set_func;
1918 part_picker_with_map->priv->i_cal_get_func = i_cal_get_func;
1919
1920 return property_part;
1921 }
1922
1923 gint
e_comp_editor_property_part_picker_with_map_get_selected(ECompEditorPropertyPartPickerWithMap * part_picker_with_map)1924 e_comp_editor_property_part_picker_with_map_get_selected (ECompEditorPropertyPartPickerWithMap *part_picker_with_map)
1925 {
1926 gint ii;
1927 const gchar *id;
1928
1929 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker_with_map), -1);
1930 g_return_val_if_fail (part_picker_with_map->priv->map != NULL, -1);
1931
1932 id = e_comp_editor_property_part_picker_get_selected_id (E_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker_with_map));
1933 if (!id)
1934 return -1;
1935
1936 ii = (gint) g_ascii_strtoll (id, NULL, 10);
1937 if (ii < 0 || ii >= part_picker_with_map->priv->n_map_elems)
1938 return -1;
1939
1940 return part_picker_with_map->priv->map[ii].value;
1941 }
1942
1943 void
e_comp_editor_property_part_picker_with_map_set_selected(ECompEditorPropertyPartPickerWithMap * part_picker_with_map,gint value)1944 e_comp_editor_property_part_picker_with_map_set_selected (ECompEditorPropertyPartPickerWithMap *part_picker_with_map,
1945 gint value)
1946 {
1947 gint ii;
1948
1949 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker_with_map));
1950 g_return_if_fail (part_picker_with_map->priv->map != NULL);
1951
1952 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1953 if (part_picker_with_map->priv->map[ii].value == value) {
1954 gchar *id;
1955
1956 id = g_strdup_printf ("%d", ii);
1957 e_comp_editor_property_part_picker_set_selected_id (
1958 E_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker_with_map), id);
1959 g_free (id);
1960
1961 return;
1962 }
1963 }
1964
1965 g_warn_if_reached ();
1966 }
1967
1968 /* ************************************************************************* */
1969