Bug 794648 - Undo/Redo doesn't work in component Description
[evolution.git] / src / calendar / gui / e-comp-editor-property-part.c
blobaafe74eac91ab6fe42acb2559ab70362c45400ba
1 /*
2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
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.
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.
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/>.
18 #include "evolution-config.h"
20 #include <glib-object.h>
21 #include <gtk/gtk.h>
23 #include <e-util/e-util.h>
25 #include "comp-util.h"
26 #include "e-comp-editor-property-part.h"
28 struct _ECompEditorPropertyPartPrivate {
29 GtkWidget *label_widget;
30 GtkWidget *edit_widget;
31 gboolean visible;
32 gboolean sensitize_handled;
35 enum {
36 PROPERTY_PART_PROP_0,
37 PROPERTY_PART_PROP_SENSITIZE_HANDLED,
38 PROPERTY_PART_PROP_VISIBLE
41 enum {
42 PROPERTY_PART_CHANGED,
43 PROPERTY_PART_LAST_SIGNAL
46 static guint property_part_signals[PROPERTY_PART_LAST_SIGNAL];
48 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPart, e_comp_editor_property_part, G_TYPE_OBJECT)
50 static void
51 e_comp_editor_property_part_set_property (GObject *object,
52 guint property_id,
53 const GValue *value,
54 GParamSpec *pspec)
56 switch (property_id) {
57 case PROPERTY_PART_PROP_SENSITIZE_HANDLED:
58 e_comp_editor_property_part_set_sensitize_handled (
59 E_COMP_EDITOR_PROPERTY_PART (object),
60 g_value_get_boolean (value));
61 return;
63 case PROPERTY_PART_PROP_VISIBLE:
64 e_comp_editor_property_part_set_visible (
65 E_COMP_EDITOR_PROPERTY_PART (object),
66 g_value_get_boolean (value));
67 return;
70 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
73 static void
74 e_comp_editor_property_part_get_property (GObject *object,
75 guint property_id,
76 GValue *value,
77 GParamSpec *pspec)
79 switch (property_id) {
80 case PROPERTY_PART_PROP_SENSITIZE_HANDLED:
81 g_value_set_boolean (
82 value,
83 e_comp_editor_property_part_get_sensitize_handled (
84 E_COMP_EDITOR_PROPERTY_PART (object)));
85 return;
87 case PROPERTY_PART_PROP_VISIBLE:
88 g_value_set_boolean (
89 value,
90 e_comp_editor_property_part_get_visible (
91 E_COMP_EDITOR_PROPERTY_PART (object)));
92 return;
95 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
98 static void
99 e_comp_editor_property_part_constructed (GObject *object)
101 ECompEditorPropertyPart *property_part;
102 GtkWidget *label_widget = NULL, *edit_widget = NULL;
104 G_OBJECT_CLASS (e_comp_editor_property_part_parent_class)->constructed (object);
106 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (object));
108 property_part = E_COMP_EDITOR_PROPERTY_PART (object);
110 e_comp_editor_property_part_create_widgets (property_part, &label_widget, &edit_widget);
112 if (label_widget) {
113 property_part->priv->label_widget = g_object_ref_sink (label_widget);
115 e_binding_bind_property (
116 property_part, "visible",
117 label_widget, "visible",
118 G_BINDING_SYNC_CREATE);
121 if (edit_widget) {
122 property_part->priv->edit_widget = g_object_ref_sink (edit_widget);
124 e_binding_bind_property (
125 property_part, "visible",
126 edit_widget, "visible",
127 G_BINDING_SYNC_CREATE);
131 static void
132 e_comp_editor_property_part_dispose (GObject *object)
134 ECompEditorPropertyPart *property_part;
136 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (object));
138 property_part = E_COMP_EDITOR_PROPERTY_PART (object);
140 g_clear_object (&property_part->priv->label_widget);
141 g_clear_object (&property_part->priv->edit_widget);
143 G_OBJECT_CLASS (e_comp_editor_property_part_parent_class)->dispose (object);
146 static void
147 e_comp_editor_property_part_init (ECompEditorPropertyPart *property_part)
149 property_part->priv = G_TYPE_INSTANCE_GET_PRIVATE (property_part,
150 E_TYPE_COMP_EDITOR_PROPERTY_PART,
151 ECompEditorPropertyPartPrivate);
152 property_part->priv->visible = TRUE;
153 property_part->priv->sensitize_handled = FALSE;
156 static void
157 e_comp_editor_property_part_class_init (ECompEditorPropertyPartClass *klass)
159 GObjectClass *object_class;
161 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPrivate));
163 object_class = G_OBJECT_CLASS (klass);
164 object_class->set_property = e_comp_editor_property_part_set_property;
165 object_class->get_property = e_comp_editor_property_part_get_property;
166 object_class->constructed = e_comp_editor_property_part_constructed;
167 object_class->dispose = e_comp_editor_property_part_dispose;
169 g_object_class_install_property (
170 object_class,
171 PROPERTY_PART_PROP_VISIBLE,
172 g_param_spec_boolean (
173 "visible",
174 "Visible",
175 "Whether the part is visible",
176 TRUE,
177 G_PARAM_READWRITE |
178 G_PARAM_STATIC_STRINGS));
180 g_object_class_install_property (
181 object_class,
182 PROPERTY_PART_PROP_SENSITIZE_HANDLED,
183 g_param_spec_boolean (
184 "sensitize-handled",
185 "Sensitize Handled",
186 "Whether the part's sensitive property is handled by the owner of it",
187 FALSE,
188 G_PARAM_READWRITE |
189 G_PARAM_STATIC_STRINGS));
191 property_part_signals[PROPERTY_PART_CHANGED] = g_signal_new (
192 "changed",
193 G_TYPE_FROM_CLASS (klass),
194 G_SIGNAL_RUN_FIRST,
195 G_STRUCT_OFFSET (ECompEditorPropertyPartClass, changed),
196 NULL, NULL, NULL,
197 G_TYPE_NONE, 0,
198 G_TYPE_NONE);
201 gboolean
202 e_comp_editor_property_part_get_visible (ECompEditorPropertyPart *property_part)
204 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), FALSE);
206 return property_part->priv->visible;
209 void
210 e_comp_editor_property_part_set_visible (ECompEditorPropertyPart *property_part,
211 gboolean visible)
213 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
215 if ((property_part->priv->visible ? 1 : 0) == (visible ? 1 : 0))
216 return;
218 property_part->priv->visible = visible;
220 g_object_notify (G_OBJECT (property_part), "visible");
223 gboolean
224 e_comp_editor_property_part_get_sensitize_handled (ECompEditorPropertyPart *property_part)
226 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), FALSE);
228 return property_part->priv->sensitize_handled;
231 void
232 e_comp_editor_property_part_set_sensitize_handled (ECompEditorPropertyPart *property_part,
233 gboolean sensitize_handled)
235 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
237 if ((property_part->priv->sensitize_handled ? 1 : 0) == (sensitize_handled ? 1 : 0))
238 return;
240 property_part->priv->sensitize_handled = sensitize_handled;
242 g_object_notify (G_OBJECT (property_part), "sensitize-handled");
245 void
246 e_comp_editor_property_part_create_widgets (ECompEditorPropertyPart *property_part,
247 GtkWidget **out_label_widget,
248 GtkWidget **out_edit_widget)
250 ECompEditorPropertyPartClass *klass;
252 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
254 g_return_if_fail (property_part->priv->label_widget == NULL);
255 g_return_if_fail (property_part->priv->edit_widget == NULL);
257 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
258 g_return_if_fail (klass->create_widgets != NULL);
260 klass->create_widgets (property_part, out_label_widget, out_edit_widget);
263 GtkWidget *
264 e_comp_editor_property_part_get_label_widget (ECompEditorPropertyPart *property_part)
266 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), NULL);
268 return property_part->priv->label_widget;
271 GtkWidget *
272 e_comp_editor_property_part_get_edit_widget (ECompEditorPropertyPart *property_part)
274 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), NULL);
276 return property_part->priv->edit_widget;
279 void
280 e_comp_editor_property_part_fill_widget (ECompEditorPropertyPart *property_part,
281 icalcomponent *component)
283 ECompEditorPropertyPartClass *klass;
285 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
287 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
288 g_return_if_fail (klass->fill_widget != NULL);
290 klass->fill_widget (property_part, component);
293 void
294 e_comp_editor_property_part_fill_component (ECompEditorPropertyPart *property_part,
295 icalcomponent *component)
297 ECompEditorPropertyPartClass *klass;
299 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
301 klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
302 g_return_if_fail (klass->fill_component != NULL);
304 klass->fill_component (property_part, component);
307 void
308 e_comp_editor_property_part_emit_changed (ECompEditorPropertyPart *property_part)
310 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
312 g_signal_emit (property_part, property_part_signals[PROPERTY_PART_CHANGED], 0, NULL);
315 /* ************************************************************************* */
317 struct _ECompEditorPropertyPartStringPrivate {
318 gboolean is_multivalue;
321 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartString, e_comp_editor_property_part_string, E_TYPE_COMP_EDITOR_PROPERTY_PART)
323 static void
324 ecepp_string_create_widgets (ECompEditorPropertyPart *property_part,
325 GtkWidget **out_label_widget,
326 GtkWidget **out_edit_widget)
328 ECompEditorPropertyPartStringClass *klass;
330 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
331 g_return_if_fail (out_label_widget != NULL);
332 g_return_if_fail (out_edit_widget != NULL);
334 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
335 g_return_if_fail (klass != NULL);
336 g_return_if_fail (g_type_is_a (klass->entry_type, GTK_TYPE_ENTRY) ||
337 g_type_is_a (klass->entry_type, GTK_TYPE_TEXT_VIEW));
339 /* The descendant sets the 'out_label_widget' parameter */
340 *out_edit_widget = g_object_new (klass->entry_type, NULL);
341 g_return_if_fail (*out_edit_widget != NULL);
343 g_object_set (G_OBJECT (*out_edit_widget),
344 "hexpand", FALSE,
345 "halign", GTK_ALIGN_FILL,
346 "vexpand", FALSE,
347 "valign", GTK_ALIGN_START,
348 NULL);
350 gtk_widget_show (*out_edit_widget);
352 if (g_type_is_a (klass->entry_type, GTK_TYPE_TEXT_VIEW)) {
353 GtkScrolledWindow *scrolled_window;
354 GtkTextBuffer *text_buffer;
356 scrolled_window = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
357 gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
358 gtk_scrolled_window_set_shadow_type (scrolled_window, GTK_SHADOW_IN);
359 gtk_widget_show (GTK_WIDGET (scrolled_window));
361 gtk_container_add (GTK_CONTAINER (scrolled_window), *out_edit_widget);
363 g_object_set (G_OBJECT (*out_edit_widget),
364 "hexpand", TRUE,
365 "halign", GTK_ALIGN_FILL,
366 "vexpand", TRUE,
367 "valign", GTK_ALIGN_FILL,
368 NULL);
370 g_object_set (G_OBJECT (scrolled_window),
371 "hexpand", FALSE,
372 "halign", GTK_ALIGN_FILL,
373 "vexpand", FALSE,
374 "valign", GTK_ALIGN_START,
375 NULL);
377 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (*out_edit_widget));
378 g_signal_connect_swapped (text_buffer, "changed",
379 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
381 *out_edit_widget = GTK_WIDGET (scrolled_window);
382 } else {
383 g_signal_connect_swapped (*out_edit_widget, "changed",
384 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
388 static void
389 ecepp_string_fill_widget (ECompEditorPropertyPart *property_part,
390 icalcomponent *component)
392 ECompEditorPropertyPartStringClass *klass;
393 GtkWidget *edit_widget;
394 GString *multivalue = NULL;
395 icalproperty *prop;
396 const gchar *value = NULL;
398 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
399 g_return_if_fail (component != NULL);
401 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
402 g_return_if_fail (GTK_IS_ENTRY (edit_widget) || GTK_IS_SCROLLED_WINDOW (edit_widget));
404 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
405 g_return_if_fail (klass != NULL);
406 g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
407 g_return_if_fail (klass->ical_get_func != NULL);
409 if (e_comp_editor_property_part_string_is_multivalue (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part))) {
410 for (prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
411 prop;
412 prop = icalcomponent_get_next_property (component, klass->ical_prop_kind)) {
413 value = klass->ical_get_func (prop);
415 if (!value || !*value)
416 continue;
418 if (!multivalue)
419 multivalue = g_string_new ("");
420 else if (multivalue->len)
421 g_string_append_c (multivalue, ',');
423 g_string_append (multivalue, value);
426 if (multivalue)
427 value = multivalue->str;
428 else
429 value = NULL;
430 } else {
431 prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
432 if (prop)
433 value = klass->ical_get_func (prop);
436 if (!value)
437 value = "";
439 if (GTK_IS_ENTRY (edit_widget)) {
440 gtk_entry_set_text (GTK_ENTRY (edit_widget), value);
441 } else /* if (GTK_IS_SCROLLED_WINDOW (edit_widget)) */ {
442 GtkTextBuffer *buffer;
444 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (edit_widget))));
445 gtk_text_buffer_set_text (buffer, value, -1);
448 e_widget_undo_reset (edit_widget);
450 if (multivalue)
451 g_string_free (multivalue, TRUE);
454 static void
455 ecepp_string_fill_component (ECompEditorPropertyPart *property_part,
456 icalcomponent *component)
458 ECompEditorPropertyPartStringClass *klass;
459 GtkWidget *edit_widget;
460 icalproperty *prop;
461 gchar *value;
463 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
464 g_return_if_fail (component != NULL);
466 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
467 g_return_if_fail (GTK_IS_ENTRY (edit_widget) || GTK_IS_SCROLLED_WINDOW (edit_widget));
469 klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
470 g_return_if_fail (klass != NULL);
471 g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
472 g_return_if_fail (klass->ical_new_func != NULL);
473 g_return_if_fail (klass->ical_set_func != NULL);
475 if (GTK_IS_ENTRY (edit_widget)) {
476 value = g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_widget)));
477 } else /* if (GTK_IS_SCROLLED_WINDOW (edit_widget)) */ {
478 GtkTextBuffer *buffer;
479 GtkTextIter text_iter_start, text_iter_end;
481 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (edit_widget))));
482 gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
483 gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
484 value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
487 if (e_comp_editor_property_part_string_is_multivalue (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part))) {
488 /* Clear all multivalues first */
489 while (prop = icalcomponent_get_first_property (component, klass->ical_prop_kind), prop) {
490 icalcomponent_remove_property (component, prop);
491 icalproperty_free (prop);
495 prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
497 if (value && *value) {
498 if (prop) {
499 klass->ical_set_func (prop, value);
500 } else {
501 prop = klass->ical_new_func (value);
502 icalcomponent_add_property (component, prop);
504 } else if (prop) {
505 icalcomponent_remove_property (component, prop);
506 icalproperty_free (prop);
509 g_free (value);
512 static void
513 e_comp_editor_property_part_string_init (ECompEditorPropertyPartString *part_string)
515 part_string->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_string,
516 E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING,
517 ECompEditorPropertyPartStringPrivate);
518 part_string->priv->is_multivalue = FALSE;
521 static void
522 e_comp_editor_property_part_string_class_init (ECompEditorPropertyPartStringClass *klass)
524 ECompEditorPropertyPartClass *part_class;
526 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartStringPrivate));
528 klass->entry_type = GTK_TYPE_ENTRY;
530 klass->ical_prop_kind = ICAL_NO_PROPERTY;
531 klass->ical_new_func = NULL;
532 klass->ical_set_func = NULL;
533 klass->ical_get_func = NULL;
535 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
536 part_class->create_widgets = ecepp_string_create_widgets;
537 part_class->fill_widget = ecepp_string_fill_widget;
538 part_class->fill_component = ecepp_string_fill_component;
541 void
542 e_comp_editor_property_part_string_attach_focus_tracker (ECompEditorPropertyPartString *part_string,
543 EFocusTracker *focus_tracker)
545 GtkWidget *edit_widget;
547 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string));
549 if (!focus_tracker)
550 return;
552 g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
554 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_string));
555 if (edit_widget) {
556 if (GTK_IS_SCROLLED_WINDOW (edit_widget))
557 e_widget_undo_attach (gtk_bin_get_child (GTK_BIN (edit_widget)), focus_tracker);
558 else
559 e_widget_undo_attach (edit_widget, focus_tracker);
563 void
564 e_comp_editor_property_part_string_set_is_multivalue (ECompEditorPropertyPartString *part_string,
565 gboolean is_multivalue)
567 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string));
569 part_string->priv->is_multivalue = is_multivalue;
572 gboolean
573 e_comp_editor_property_part_string_is_multivalue (ECompEditorPropertyPartString *part_string)
575 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string), FALSE);
577 return part_string->priv->is_multivalue;
580 /* ************************************************************************* */
582 struct _ECompEditorPropertyPartDatetimePrivate {
583 GWeakRef timezone_entry;
586 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartDatetime, e_comp_editor_property_part_datetime, E_TYPE_COMP_EDITOR_PROPERTY_PART)
588 static void
589 ecepp_datetime_create_widgets (ECompEditorPropertyPart *property_part,
590 GtkWidget **out_label_widget,
591 GtkWidget **out_edit_widget)
593 ECompEditorPropertyPartDatetimeClass *klass;
595 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
596 g_return_if_fail (out_label_widget != NULL);
597 g_return_if_fail (out_edit_widget != NULL);
599 klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
600 g_return_if_fail (klass != NULL);
602 /* The descendant sets the 'out_label_widget' parameter */
603 *out_edit_widget = e_date_edit_new ();
604 g_return_if_fail (*out_edit_widget != NULL);
606 g_object_set (G_OBJECT (*out_edit_widget),
607 "hexpand", FALSE,
608 "halign", GTK_ALIGN_START,
609 "vexpand", FALSE,
610 "valign", GTK_ALIGN_START,
611 NULL);
613 gtk_widget_show (*out_edit_widget);
615 g_signal_connect_swapped (*out_edit_widget, "changed",
616 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
617 g_signal_connect_swapped (*out_edit_widget, "notify::show-time",
618 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
621 static void
622 ecepp_datetime_fill_widget (ECompEditorPropertyPart *property_part,
623 icalcomponent *component)
625 ECompEditorPropertyPartDatetime *part_datetime;
626 ECompEditorPropertyPartDatetimeClass *klass;
627 GtkWidget *edit_widget;
628 icalproperty *prop;
629 struct icaltimetype value;
631 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
632 g_return_if_fail (component != NULL);
634 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
635 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
637 klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
638 g_return_if_fail (klass != NULL);
639 g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
640 g_return_if_fail (klass->ical_get_func != NULL);
642 part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part);
644 prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
645 if (prop)
646 value = klass->ical_get_func (prop);
647 else
648 value = icaltime_null_time ();
650 e_comp_editor_property_part_datetime_set_value (part_datetime, value);
653 static void
654 ecepp_datetime_fill_component (ECompEditorPropertyPart *property_part,
655 icalcomponent *component)
657 ECompEditorPropertyPartDatetime *part_datetime;
658 ECompEditorPropertyPartDatetimeClass *klass;
659 GtkWidget *edit_widget;
660 EDateEdit *date_edit;
661 icalproperty *prop;
662 struct icaltimetype value;
663 time_t tt;
665 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
666 g_return_if_fail (component != NULL);
668 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
669 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
671 klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
672 g_return_if_fail (klass != NULL);
673 g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
674 g_return_if_fail (klass->ical_new_func != NULL);
675 g_return_if_fail (klass->ical_set_func != NULL);
677 part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part);
678 date_edit = E_DATE_EDIT (edit_widget);
679 tt = e_date_edit_get_time (date_edit);
681 prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
683 if (e_date_edit_get_allow_no_date_set (date_edit) && tt == (time_t) -1) {
684 if (prop) {
685 icalcomponent_remove_property (component, prop);
686 icalproperty_free (prop);
688 } else {
689 value = e_comp_editor_property_part_datetime_get_value (part_datetime);
691 if (prop) {
692 klass->ical_set_func (prop, value);
693 cal_comp_util_update_tzid_parameter (prop, value);
694 } else {
695 prop = klass->ical_new_func (value);
696 cal_comp_util_update_tzid_parameter (prop, value);
697 icalcomponent_add_property (component, prop);
702 static void
703 ecepp_datetime_finalize (GObject *object)
705 ECompEditorPropertyPartDatetime *part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (object);
707 g_weak_ref_clear (&part_datetime->priv->timezone_entry);
709 G_OBJECT_CLASS (e_comp_editor_property_part_datetime_parent_class)->finalize (object);
712 static void
713 e_comp_editor_property_part_datetime_init (ECompEditorPropertyPartDatetime *part_datetime)
715 part_datetime->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_datetime,
716 E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME,
717 ECompEditorPropertyPartDatetimePrivate);
719 g_weak_ref_init (&part_datetime->priv->timezone_entry, NULL);
722 static void
723 e_comp_editor_property_part_datetime_class_init (ECompEditorPropertyPartDatetimeClass *klass)
725 ECompEditorPropertyPartClass *part_class;
726 GObjectClass *object_class;
728 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartDatetimePrivate));
730 klass->ical_prop_kind = ICAL_NO_PROPERTY;
731 klass->ical_new_func = NULL;
732 klass->ical_set_func = NULL;
733 klass->ical_get_func = NULL;
735 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
736 part_class->create_widgets = ecepp_datetime_create_widgets;
737 part_class->fill_widget = ecepp_datetime_fill_widget;
738 part_class->fill_component = ecepp_datetime_fill_component;
740 object_class = G_OBJECT_CLASS (klass);
741 object_class->finalize = ecepp_datetime_finalize;
744 void
745 e_comp_editor_property_part_datetime_attach_timezone_entry (ECompEditorPropertyPartDatetime *part_datetime,
746 ETimezoneEntry *timezone_entry)
748 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
749 if (timezone_entry)
750 g_return_if_fail (E_IS_TIMEZONE_ENTRY (timezone_entry));
752 g_weak_ref_set (&part_datetime->priv->timezone_entry, timezone_entry);
755 void
756 e_comp_editor_property_part_datetime_set_date_only (ECompEditorPropertyPartDatetime *part_datetime,
757 gboolean date_only)
759 GtkWidget *edit_widget;
761 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
763 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
764 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
766 if ((e_date_edit_get_show_time (E_DATE_EDIT (edit_widget)) ? 1 : 0) == ((!date_only) ? 1 : 0))
767 return;
769 e_date_edit_set_show_time (E_DATE_EDIT (edit_widget), !date_only);
772 gboolean
773 e_comp_editor_property_part_datetime_get_date_only (ECompEditorPropertyPartDatetime *part_datetime)
775 GtkWidget *edit_widget;
777 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
779 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
780 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
782 return !e_date_edit_get_show_time (E_DATE_EDIT (edit_widget));
785 void
786 e_comp_editor_property_part_datetime_set_allow_no_date_set (ECompEditorPropertyPartDatetime *part_datetime,
787 gboolean allow_no_date_set)
789 GtkWidget *edit_widget;
791 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
793 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
794 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
796 e_date_edit_set_allow_no_date_set (E_DATE_EDIT (edit_widget), allow_no_date_set);
799 gboolean
800 e_comp_editor_property_part_datetime_get_allow_no_date_set (ECompEditorPropertyPartDatetime *part_datetime)
802 GtkWidget *edit_widget;
804 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
806 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
807 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
809 return !e_date_edit_get_allow_no_date_set (E_DATE_EDIT (edit_widget));
812 void
813 e_comp_editor_property_part_datetime_set_value (ECompEditorPropertyPartDatetime *part_datetime,
814 struct icaltimetype value)
816 GtkWidget *edit_widget;
817 EDateEdit *date_edit;
819 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
821 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
822 g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
824 date_edit = E_DATE_EDIT (edit_widget);
826 if (!e_date_edit_get_allow_no_date_set (date_edit) && (icaltime_is_null_time (value) ||
827 !icaltime_is_valid_time (value))) {
828 value = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
831 if (icaltime_is_null_time (value) ||
832 !icaltime_is_valid_time (value)) {
833 e_date_edit_set_time (date_edit, (time_t) -1);
834 } else {
835 e_date_edit_set_date (date_edit, value.year, value.month, value.day);
837 if (!value.is_date)
838 e_date_edit_set_time_of_day (date_edit, value.hour, value.minute);
839 else if (e_date_edit_get_show_time (date_edit))
840 e_date_edit_set_time_of_day (date_edit, 0, 0);
841 else if (e_date_edit_get_allow_no_date_set (date_edit))
842 e_date_edit_set_time_of_day (date_edit, -1, -1);
844 e_comp_editor_property_part_datetime_set_date_only (part_datetime, value.is_date);
848 struct icaltimetype
849 e_comp_editor_property_part_datetime_get_value (ECompEditorPropertyPartDatetime *part_datetime)
851 ETimezoneEntry *timezone_entry = NULL;
852 GtkWidget *edit_widget;
853 EDateEdit *date_edit;
854 struct icaltimetype value = icaltime_null_time ();
856 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), value);
858 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
859 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), value);
861 date_edit = E_DATE_EDIT (edit_widget);
863 if (!e_date_edit_get_date (date_edit, &value.year, &value.month, &value.day))
864 return icaltime_null_time ();
866 if (!e_date_edit_get_show_time (date_edit)) {
867 value.is_date = 1;
868 } else {
869 value.zone = NULL;
870 value.is_date = !e_date_edit_get_time_of_day (date_edit, &value.hour, &value.minute);
872 if (!value.is_date) {
873 timezone_entry = g_weak_ref_get (&part_datetime->priv->timezone_entry);
874 if (timezone_entry)
875 value.zone = e_timezone_entry_get_timezone (timezone_entry);
876 if (!value.zone)
877 value.zone = icaltimezone_get_utc_timezone ();
881 g_clear_object (&timezone_entry);
883 return value;
886 gboolean
887 e_comp_editor_property_part_datetime_check_validity (ECompEditorPropertyPartDatetime *part_datetime,
888 gboolean *out_date_is_valid,
889 gboolean *out_time_is_valid)
891 GtkWidget *edit_widget;
892 EDateEdit *date_edit;
893 gboolean date_is_valid = TRUE, time_is_valid = TRUE;
895 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
897 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
898 g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
900 date_edit = E_DATE_EDIT (edit_widget);
902 if (!e_date_edit_get_allow_no_date_set (date_edit) ||
903 e_date_edit_get_time (date_edit) != (time_t) -1) {
904 date_is_valid = e_date_edit_date_is_valid (date_edit);
906 if (e_date_edit_get_show_time (date_edit))
907 time_is_valid = e_date_edit_time_is_valid (date_edit);
910 if (out_date_is_valid)
911 *out_date_is_valid = date_is_valid;
912 if (out_time_is_valid)
913 *out_time_is_valid = time_is_valid;
915 return date_is_valid && time_is_valid;
918 /* ************************************************************************* */
920 struct _ECompEditorPropertyPartSpinPrivate {
921 gint dummy;
924 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartSpin, e_comp_editor_property_part_spin, E_TYPE_COMP_EDITOR_PROPERTY_PART)
926 static void
927 ecepp_spin_create_widgets (ECompEditorPropertyPart *property_part,
928 GtkWidget **out_label_widget,
929 GtkWidget **out_edit_widget)
931 ECompEditorPropertyPartSpinClass *klass;
933 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
934 g_return_if_fail (out_label_widget != NULL);
935 g_return_if_fail (out_edit_widget != NULL);
937 klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
938 g_return_if_fail (klass != NULL);
940 /* The descendant sets the 'out_label_widget' parameter */
941 *out_edit_widget = gtk_spin_button_new_with_range (-10, 10, 1);
942 g_return_if_fail (*out_edit_widget != NULL);
944 g_object_set (G_OBJECT (*out_edit_widget),
945 "hexpand", FALSE,
946 "halign", GTK_ALIGN_FILL,
947 "vexpand", FALSE,
948 "valign", GTK_ALIGN_START,
949 NULL);
951 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (*out_edit_widget), 0);
953 gtk_widget_show (*out_edit_widget);
955 g_signal_connect_swapped (*out_edit_widget, "value-changed",
956 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
959 static void
960 ecepp_spin_fill_widget (ECompEditorPropertyPart *property_part,
961 icalcomponent *component)
963 ECompEditorPropertyPartSpinClass *klass;
964 GtkWidget *edit_widget;
965 icalproperty *prop;
966 gint value;
968 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
969 g_return_if_fail (component != NULL);
971 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
972 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
974 klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
975 g_return_if_fail (klass != NULL);
976 g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
977 g_return_if_fail (klass->ical_get_func != NULL);
979 prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
980 if (prop) {
981 value = klass->ical_get_func (prop);
982 } else {
983 gdouble d_min, d_max;
985 gtk_spin_button_get_range (GTK_SPIN_BUTTON (edit_widget), &d_min, &d_max);
987 value = (gint) d_min;
990 gtk_spin_button_set_value (GTK_SPIN_BUTTON (edit_widget), value);
993 static void
994 ecepp_spin_fill_component (ECompEditorPropertyPart *property_part,
995 icalcomponent *component)
997 ECompEditorPropertyPartSpinClass *klass;
998 GtkWidget *edit_widget;
999 icalproperty *prop;
1000 gint value;
1002 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
1003 g_return_if_fail (component != NULL);
1005 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1006 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1008 klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
1009 g_return_if_fail (klass != NULL);
1010 g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
1011 g_return_if_fail (klass->ical_new_func != NULL);
1012 g_return_if_fail (klass->ical_set_func != NULL);
1014 value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (edit_widget));
1015 prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
1017 if (prop) {
1018 klass->ical_set_func (prop, value);
1019 } else {
1020 prop = klass->ical_new_func (value);
1021 icalcomponent_add_property (component, prop);
1025 static void
1026 e_comp_editor_property_part_spin_init (ECompEditorPropertyPartSpin *part_spin)
1028 part_spin->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_spin,
1029 E_TYPE_COMP_EDITOR_PROPERTY_PART_SPIN,
1030 ECompEditorPropertyPartSpinPrivate);
1033 static void
1034 e_comp_editor_property_part_spin_class_init (ECompEditorPropertyPartSpinClass *klass)
1036 ECompEditorPropertyPartClass *part_class;
1038 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartSpinPrivate));
1040 klass->ical_prop_kind = ICAL_NO_PROPERTY;
1041 klass->ical_new_func = NULL;
1042 klass->ical_set_func = NULL;
1043 klass->ical_get_func = NULL;
1045 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1046 part_class->create_widgets = ecepp_spin_create_widgets;
1047 part_class->fill_widget = ecepp_spin_fill_widget;
1048 part_class->fill_component = ecepp_spin_fill_component;
1051 void
1052 e_comp_editor_property_part_spin_set_range (ECompEditorPropertyPartSpin *part_spin,
1053 gint min_value,
1054 gint max_value)
1056 GtkWidget *edit_widget;
1058 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (part_spin));
1060 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_spin));
1061 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1063 gtk_spin_button_set_range (GTK_SPIN_BUTTON (edit_widget), min_value, max_value);
1066 void
1067 e_comp_editor_property_part_spin_get_range (ECompEditorPropertyPartSpin *part_spin,
1068 gint *out_min_value,
1069 gint *out_max_value)
1071 GtkWidget *edit_widget;
1072 gdouble d_min = 0, d_max = 0;
1074 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (part_spin));
1076 edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_spin));
1077 g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
1079 gtk_spin_button_get_range (GTK_SPIN_BUTTON (edit_widget), &d_min, &d_max);
1081 if (out_min_value)
1082 *out_min_value = (gint) d_min;
1083 if (out_max_value)
1084 *out_max_value = (gint) d_max;
1087 /* ************************************************************************* */
1089 struct _ECompEditorPropertyPartPickerPrivate {
1090 gint dummy;
1093 G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartPicker, e_comp_editor_property_part_picker, E_TYPE_COMP_EDITOR_PROPERTY_PART)
1095 static void
1096 ecepp_picker_create_widgets (ECompEditorPropertyPart *property_part,
1097 GtkWidget **out_label_widget,
1098 GtkWidget **out_edit_widget)
1100 ECompEditorPropertyPartPickerClass *klass;
1101 GtkComboBoxText *combo_box;
1102 GSList *ids = NULL, *display_names = NULL, *i_link, *dn_link;
1104 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
1105 g_return_if_fail (out_label_widget != NULL);
1106 g_return_if_fail (out_edit_widget != NULL);
1108 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (property_part);
1109 g_return_if_fail (klass != NULL);
1111 /* The descendant sets the 'out_label_widget' parameter */
1112 *out_edit_widget = gtk_combo_box_text_new ();
1113 g_return_if_fail (*out_edit_widget != NULL);
1115 g_object_set (G_OBJECT (*out_edit_widget),
1116 "hexpand", FALSE,
1117 "halign", GTK_ALIGN_FILL,
1118 "vexpand", FALSE,
1119 "valign", GTK_ALIGN_START,
1120 NULL);
1122 gtk_widget_show (*out_edit_widget);
1124 e_comp_editor_property_part_picker_get_values (E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
1125 &ids, &display_names);
1127 g_warn_if_fail (g_slist_length (ids) == g_slist_length (display_names));
1129 combo_box = GTK_COMBO_BOX_TEXT (*out_edit_widget);
1131 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)) {
1132 const gchar *id, *display_name;
1134 id = i_link->data;
1135 display_name = dn_link->data;
1137 g_warn_if_fail (id != NULL);
1138 g_warn_if_fail (display_name != NULL);
1140 if (!id || !display_name)
1141 continue;
1143 gtk_combo_box_text_append (combo_box, id, display_name);
1146 g_slist_free_full (ids, g_free);
1147 g_slist_free_full (display_names, g_free);
1149 g_signal_connect_swapped (*out_edit_widget, "changed",
1150 G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
1153 static void
1154 ecepp_picker_fill_widget (ECompEditorPropertyPart *property_part,
1155 icalcomponent *component)
1157 GtkWidget *edit_widget;
1158 gchar *id = NULL;
1160 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
1161 g_return_if_fail (component != NULL);
1163 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1164 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
1166 if (e_comp_editor_property_part_picker_get_from_component (
1167 E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
1168 component, &id) && id) {
1169 gtk_combo_box_set_active_id (GTK_COMBO_BOX (edit_widget), id);
1170 g_free (id);
1171 } else {
1172 gtk_combo_box_set_active (GTK_COMBO_BOX (edit_widget), 0);
1176 static void
1177 ecepp_picker_fill_component (ECompEditorPropertyPart *property_part,
1178 icalcomponent *component)
1180 GtkWidget *edit_widget;
1181 const gchar *id;
1183 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
1184 g_return_if_fail (component != NULL);
1186 edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
1187 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
1189 id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (edit_widget));
1190 if (id) {
1191 e_comp_editor_property_part_picker_set_to_component (
1192 E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
1193 id, component);
1197 static void
1198 e_comp_editor_property_part_picker_init (ECompEditorPropertyPartPicker *part_picker)
1200 part_picker->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_picker,
1201 E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER,
1202 ECompEditorPropertyPartPickerPrivate);
1205 static void
1206 e_comp_editor_property_part_picker_class_init (ECompEditorPropertyPartPickerClass *klass)
1208 ECompEditorPropertyPartClass *part_class;
1210 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPickerPrivate));
1212 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1213 part_class->create_widgets = ecepp_picker_create_widgets;
1214 part_class->fill_widget = ecepp_picker_fill_widget;
1215 part_class->fill_component = ecepp_picker_fill_component;
1218 /* Both out_ids and out_display_names contain newly allocated strings,
1219 where also n-th element of out_uids corresponds to n-th element of
1220 the out_display_names. */
1221 void
1222 e_comp_editor_property_part_picker_get_values (ECompEditorPropertyPartPicker *part_picker,
1223 GSList **out_ids,
1224 GSList **out_display_names)
1226 ECompEditorPropertyPartPickerClass *klass;
1228 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
1230 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
1231 g_return_if_fail (klass != NULL);
1232 g_return_if_fail (klass->get_values != NULL);
1234 klass->get_values (part_picker, out_ids, out_display_names);
1237 gboolean
1238 e_comp_editor_property_part_picker_get_from_component (ECompEditorPropertyPartPicker *part_picker,
1239 icalcomponent *component,
1240 gchar **out_id)
1242 ECompEditorPropertyPartPickerClass *klass;
1244 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker), FALSE);
1246 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
1247 g_return_val_if_fail (klass != NULL, FALSE);
1248 g_return_val_if_fail (klass->get_from_component != NULL, FALSE);
1250 return klass->get_from_component (part_picker, component, out_id);
1253 void
1254 e_comp_editor_property_part_picker_set_to_component (ECompEditorPropertyPartPicker *part_picker,
1255 const gchar *id,
1256 icalcomponent *component)
1258 ECompEditorPropertyPartPickerClass *klass;
1260 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
1262 klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
1263 g_return_if_fail (klass != NULL);
1264 g_return_if_fail (klass->set_to_component != NULL);
1266 klass->set_to_component (part_picker, id, component);
1269 const gchar *
1270 e_comp_editor_property_part_picker_get_selected_id (ECompEditorPropertyPartPicker *part_picker)
1272 GtkWidget *edit_widget;
1274 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker), NULL);
1276 edit_widget = e_comp_editor_property_part_get_edit_widget (
1277 E_COMP_EDITOR_PROPERTY_PART (part_picker));
1278 g_return_val_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget), NULL);
1280 return gtk_combo_box_get_active_id (GTK_COMBO_BOX (edit_widget));
1283 void
1284 e_comp_editor_property_part_picker_set_selected_id (ECompEditorPropertyPartPicker *part_picker,
1285 const gchar *id)
1287 GtkWidget *edit_widget;
1289 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
1290 g_return_if_fail (id != NULL);
1292 edit_widget = e_comp_editor_property_part_get_edit_widget (
1293 E_COMP_EDITOR_PROPERTY_PART (part_picker));
1294 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
1296 gtk_combo_box_set_active_id (GTK_COMBO_BOX (edit_widget), id);
1299 /* ************************************************************************* */
1301 struct _ECompEditorPropertyPartPickerWithMapPrivate {
1302 ECompEditorPropertyPartPickerMap *map;
1303 gint n_map_elems;
1304 gchar *label;
1306 icalproperty_kind ical_prop_kind;
1307 ECompEditorPropertyPartPickerMapICalNewFunc ical_new_func;
1308 ECompEditorPropertyPartPickerMapICalSetFunc ical_set_func;
1309 ECompEditorPropertyPartPickerMapICalGetFunc ical_get_func;
1312 enum {
1313 PICKER_WITH_MAP_PROP_0,
1314 PICKER_WITH_MAP_PROP_MAP,
1315 PICKER_WITH_MAP_PROP_LABEL
1318 G_DEFINE_TYPE (ECompEditorPropertyPartPickerWithMap, e_comp_editor_property_part_picker_with_map, E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER)
1320 static void
1321 ecepp_picker_with_map_get_values (ECompEditorPropertyPartPicker *part_picker,
1322 GSList **out_ids,
1323 GSList **out_display_names)
1325 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1326 gint ii;
1328 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker));
1329 g_return_if_fail (out_ids != NULL);
1330 g_return_if_fail (out_display_names != NULL);
1332 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
1333 g_return_if_fail (part_picker_with_map->priv->map != NULL);
1334 g_return_if_fail (part_picker_with_map->priv->n_map_elems > 0);
1336 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1337 *out_ids = g_slist_prepend (*out_ids, g_strdup_printf ("%d", ii));
1338 *out_display_names = g_slist_prepend (*out_display_names,
1339 g_strdup (part_picker_with_map->priv->map[ii].description));
1342 *out_ids = g_slist_reverse (*out_ids);
1343 *out_display_names = g_slist_reverse (*out_display_names);
1346 static gboolean
1347 ecepp_picker_with_map_get_from_component (ECompEditorPropertyPartPicker *part_picker,
1348 icalcomponent *component,
1349 gchar **out_id)
1351 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1352 icalproperty *prop;
1353 gint ii, value;
1355 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker), FALSE);
1356 g_return_val_if_fail (component != NULL, FALSE);
1357 g_return_val_if_fail (out_id != NULL, FALSE);
1359 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
1360 g_return_val_if_fail (part_picker_with_map->priv->map != NULL, FALSE);
1361 g_return_val_if_fail (part_picker_with_map->priv->n_map_elems > 0, FALSE);
1362 g_return_val_if_fail (part_picker_with_map->priv->ical_prop_kind != ICAL_NO_PROPERTY, FALSE);
1363 g_return_val_if_fail (part_picker_with_map->priv->ical_get_func != NULL, FALSE);
1365 prop = icalcomponent_get_first_property (component, part_picker_with_map->priv->ical_prop_kind);
1366 if (!prop)
1367 return FALSE;
1369 value = part_picker_with_map->priv->ical_get_func (prop);
1371 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1372 gboolean matches;
1374 if (part_picker_with_map->priv->map[ii].matches_func) {
1375 matches = part_picker_with_map->priv->map[ii].matches_func (part_picker_with_map->priv->map[ii].value, value);
1376 } else {
1377 matches = value == part_picker_with_map->priv->map[ii].value;
1380 if (matches) {
1381 *out_id = g_strdup_printf ("%d", ii);
1382 return TRUE;
1386 return FALSE;
1389 static void
1390 ecepp_picker_with_map_set_to_component (ECompEditorPropertyPartPicker *part_picker,
1391 const gchar *id,
1392 icalcomponent *component)
1394 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1395 icalproperty *prop;
1396 gint ii, value;
1398 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker));
1399 g_return_if_fail (id != NULL);
1400 g_return_if_fail (component != NULL);
1402 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
1403 g_return_if_fail (part_picker_with_map->priv->map != NULL);
1404 g_return_if_fail (part_picker_with_map->priv->n_map_elems > 0);
1405 g_return_if_fail (part_picker_with_map->priv->ical_prop_kind != ICAL_NO_PROPERTY);
1406 g_return_if_fail (part_picker_with_map->priv->ical_new_func != NULL);
1407 g_return_if_fail (part_picker_with_map->priv->ical_set_func != NULL);
1409 ii = (gint) g_ascii_strtoll (id, NULL, 10);
1410 g_return_if_fail (ii >= 0 && ii < part_picker_with_map->priv->n_map_elems);
1412 prop = icalcomponent_get_first_property (component, part_picker_with_map->priv->ical_prop_kind);
1413 value = part_picker_with_map->priv->map[ii].value;
1415 if (part_picker_with_map->priv->map[ii].delete_prop) {
1416 if (prop) {
1417 icalcomponent_remove_property (component, prop);
1418 icalproperty_free (prop);
1420 } else if (prop) {
1421 part_picker_with_map->priv->ical_set_func (prop, value);
1422 } else {
1423 prop = part_picker_with_map->priv->ical_new_func (value);
1424 icalcomponent_add_property (component, prop);
1428 static void
1429 ecepp_picker_with_map_create_widgets (ECompEditorPropertyPart *property_part,
1430 GtkWidget **out_label_widget,
1431 GtkWidget **out_edit_widget)
1433 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1434 ECompEditorPropertyPartClass *part_class;
1436 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part));
1437 g_return_if_fail (out_label_widget != NULL);
1438 g_return_if_fail (out_edit_widget != NULL);
1440 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_picker_with_map_parent_class);
1441 g_return_if_fail (part_class != NULL);
1442 g_return_if_fail (part_class->create_widgets != NULL);
1444 *out_label_widget = NULL;
1446 part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
1447 g_return_if_fail (*out_label_widget == NULL);
1448 g_return_if_fail (*out_edit_widget != NULL);
1450 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part);
1452 *out_label_widget = gtk_label_new_with_mnemonic (part_picker_with_map->priv->label);
1453 gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
1455 g_object_set (G_OBJECT (*out_label_widget),
1456 "hexpand", FALSE,
1457 "halign", GTK_ALIGN_END,
1458 "vexpand", FALSE,
1459 "valign", GTK_ALIGN_CENTER,
1460 NULL);
1462 gtk_widget_show (*out_label_widget);
1465 static void
1466 ecepp_picker_with_map_set_property (GObject *object,
1467 guint property_id,
1468 const GValue *value,
1469 GParamSpec *pspec)
1471 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1472 gint ii;
1474 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object));
1476 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object);
1478 switch (property_id) {
1479 case PICKER_WITH_MAP_PROP_MAP:
1480 g_return_if_fail (part_picker_with_map->priv->map == NULL);
1482 part_picker_with_map->priv->map = g_value_get_pointer (value);
1483 for (ii = 0; part_picker_with_map->priv->map[ii].description; ii++) {
1484 /* pre-count elements */
1487 part_picker_with_map->priv->n_map_elems = ii;
1488 return;
1490 case PICKER_WITH_MAP_PROP_LABEL:
1491 g_free (part_picker_with_map->priv->label);
1492 part_picker_with_map->priv->label = g_value_dup_string (value);
1493 return;
1496 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1499 static void
1500 ecepp_picker_with_map_finalize (GObject *object)
1502 ECompEditorPropertyPartPickerWithMap *part_picker_with_map =
1503 E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object);
1505 if (part_picker_with_map->priv->map && part_picker_with_map->priv->n_map_elems > 0) {
1506 gint ii;
1508 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1509 g_free ((gchar *) part_picker_with_map->priv->map[ii].description);
1512 g_free (part_picker_with_map->priv->map);
1513 part_picker_with_map->priv->map = NULL;
1516 g_free (part_picker_with_map->priv->label);
1517 part_picker_with_map->priv->label = NULL;
1519 G_OBJECT_CLASS (e_comp_editor_property_part_picker_with_map_parent_class)->finalize (object);
1522 static void
1523 e_comp_editor_property_part_picker_with_map_init (ECompEditorPropertyPartPickerWithMap *part_picker_with_map)
1525 part_picker_with_map->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_picker_with_map,
1526 E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP,
1527 ECompEditorPropertyPartPickerWithMapPrivate);
1530 static void
1531 e_comp_editor_property_part_picker_with_map_class_init (ECompEditorPropertyPartPickerWithMapClass *klass)
1533 ECompEditorPropertyPartPickerClass *part_picker_class;
1534 ECompEditorPropertyPartClass *part_class;
1535 GObjectClass *object_class;
1537 g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPickerWithMapPrivate));
1539 part_picker_class = E_COMP_EDITOR_PROPERTY_PART_PICKER_CLASS (klass);
1540 part_picker_class->get_values = ecepp_picker_with_map_get_values;
1541 part_picker_class->get_from_component = ecepp_picker_with_map_get_from_component;
1542 part_picker_class->set_to_component = ecepp_picker_with_map_set_to_component;
1544 part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
1545 part_class->create_widgets = ecepp_picker_with_map_create_widgets;
1547 object_class = G_OBJECT_CLASS (klass);
1548 object_class->set_property = ecepp_picker_with_map_set_property;
1549 object_class->finalize = ecepp_picker_with_map_finalize;
1551 g_object_class_install_property (
1552 object_class,
1553 PICKER_WITH_MAP_PROP_MAP,
1554 g_param_spec_pointer (
1555 "map",
1556 "Map",
1557 "Map of values, .description-NULL-terminated",
1558 G_PARAM_WRITABLE |
1559 G_PARAM_CONSTRUCT_ONLY |
1560 G_PARAM_STATIC_STRINGS));
1562 g_object_class_install_property (
1563 object_class,
1564 PICKER_WITH_MAP_PROP_LABEL,
1565 g_param_spec_string (
1566 "label",
1567 "Label",
1568 "Label of the picker",
1569 NULL,
1570 G_PARAM_WRITABLE |
1571 G_PARAM_CONSTRUCT_ONLY |
1572 G_PARAM_STATIC_STRINGS));
1575 ECompEditorPropertyPart *
1576 e_comp_editor_property_part_picker_with_map_new (const ECompEditorPropertyPartPickerMap map[],
1577 gint n_map_elements,
1578 const gchar *label,
1579 icalproperty_kind ical_prop_kind,
1580 ECompEditorPropertyPartPickerMapICalNewFunc ical_new_func,
1581 ECompEditorPropertyPartPickerMapICalSetFunc ical_set_func,
1582 ECompEditorPropertyPartPickerMapICalGetFunc ical_get_func)
1584 ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
1585 ECompEditorPropertyPartPickerMap *map_copy;
1586 ECompEditorPropertyPart *property_part;
1587 gint ii;
1589 g_return_val_if_fail (map != NULL, NULL);
1590 g_return_val_if_fail (n_map_elements > 0, NULL);
1591 g_return_val_if_fail (label != NULL, NULL);
1592 g_return_val_if_fail (ical_prop_kind != ICAL_NO_PROPERTY, NULL);
1593 g_return_val_if_fail (ical_new_func != NULL, NULL);
1594 g_return_val_if_fail (ical_set_func != NULL, NULL);
1595 g_return_val_if_fail (ical_get_func != NULL, NULL);
1597 map_copy = g_new0 (ECompEditorPropertyPartPickerMap, n_map_elements + 1);
1598 for (ii = 0; ii < n_map_elements; ii++) {
1599 map_copy[ii] = map[ii];
1600 map_copy[ii].description = g_strdup (map[ii].description);
1603 property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP,
1604 "map", map_copy,
1605 "label", label,
1606 NULL);
1608 part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part);
1610 part_picker_with_map->priv->ical_prop_kind = ical_prop_kind;
1611 part_picker_with_map->priv->ical_new_func = ical_new_func;
1612 part_picker_with_map->priv->ical_set_func = ical_set_func;
1613 part_picker_with_map->priv->ical_get_func = ical_get_func;
1615 return property_part;
1618 gint
1619 e_comp_editor_property_part_picker_with_map_get_selected (ECompEditorPropertyPartPickerWithMap *part_picker_with_map)
1621 gint ii;
1622 const gchar *id;
1624 g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker_with_map), -1);
1625 g_return_val_if_fail (part_picker_with_map->priv->map != NULL, -1);
1627 id = e_comp_editor_property_part_picker_get_selected_id (E_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker_with_map));
1628 if (!id)
1629 return -1;
1631 ii = (gint) g_ascii_strtoll (id, NULL, 10);
1632 if (ii < 0 || ii >= part_picker_with_map->priv->n_map_elems)
1633 return -1;
1635 return part_picker_with_map->priv->map[ii].value;
1638 void
1639 e_comp_editor_property_part_picker_with_map_set_selected (ECompEditorPropertyPartPickerWithMap *part_picker_with_map,
1640 gint value)
1642 gint ii;
1644 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker_with_map));
1645 g_return_if_fail (part_picker_with_map->priv->map != NULL);
1647 for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
1648 if (part_picker_with_map->priv->map[ii].value == value) {
1649 gchar *id;
1651 id = g_strdup_printf ("%d", ii);
1652 e_comp_editor_property_part_picker_set_selected_id (
1653 E_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker_with_map), id);
1654 g_free (id);
1656 return;
1660 g_warn_if_reached ();
1663 /* ************************************************************************* */