/*
* Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "evolution-config.h"
#include <glib-object.h>
#include <gtk/gtk.h>
#include <e-util/e-util.h>
#include "comp-util.h"
#include "e-comp-editor-property-part.h"
struct _ECompEditorPropertyPartPrivate {
GtkWidget *label_widget;
GtkWidget *edit_widget;
gboolean visible;
gboolean sensitize_handled;
};
enum {
PROPERTY_PART_PROP_0,
PROPERTY_PART_PROP_SENSITIZE_HANDLED,
PROPERTY_PART_PROP_VISIBLE
};
enum {
PROPERTY_PART_CHANGED,
PROPERTY_PART_LAST_SIGNAL
};
static guint property_part_signals[PROPERTY_PART_LAST_SIGNAL];
G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPart, e_comp_editor_property_part, G_TYPE_OBJECT)
static void
e_comp_editor_property_part_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROPERTY_PART_PROP_SENSITIZE_HANDLED:
e_comp_editor_property_part_set_sensitize_handled (
E_COMP_EDITOR_PROPERTY_PART (object),
g_value_get_boolean (value));
return;
case PROPERTY_PART_PROP_VISIBLE:
e_comp_editor_property_part_set_visible (
E_COMP_EDITOR_PROPERTY_PART (object),
g_value_get_boolean (value));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
e_comp_editor_property_part_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROPERTY_PART_PROP_SENSITIZE_HANDLED:
g_value_set_boolean (
value,
e_comp_editor_property_part_get_sensitize_handled (
E_COMP_EDITOR_PROPERTY_PART (object)));
return;
case PROPERTY_PART_PROP_VISIBLE:
g_value_set_boolean (
value,
e_comp_editor_property_part_get_visible (
E_COMP_EDITOR_PROPERTY_PART (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
e_comp_editor_property_part_constructed (GObject *object)
{
ECompEditorPropertyPart *property_part;
GtkWidget *label_widget = NULL, *edit_widget = NULL;
G_OBJECT_CLASS (e_comp_editor_property_part_parent_class)->constructed (object);
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (object));
property_part = E_COMP_EDITOR_PROPERTY_PART (object);
e_comp_editor_property_part_create_widgets (property_part, &label_widget, &edit_widget);
if (label_widget) {
property_part->priv->label_widget = g_object_ref_sink (label_widget);
e_binding_bind_property (
property_part, "visible",
label_widget, "visible",
G_BINDING_SYNC_CREATE);
}
if (edit_widget) {
property_part->priv->edit_widget = g_object_ref_sink (edit_widget);
e_binding_bind_property (
property_part, "visible",
edit_widget, "visible",
G_BINDING_SYNC_CREATE);
}
}
static void
e_comp_editor_property_part_dispose (GObject *object)
{
ECompEditorPropertyPart *property_part;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (object));
property_part = E_COMP_EDITOR_PROPERTY_PART (object);
g_clear_object (&property_part->priv->label_widget);
g_clear_object (&property_part->priv->edit_widget);
G_OBJECT_CLASS (e_comp_editor_property_part_parent_class)->dispose (object);
}
static void
e_comp_editor_property_part_init (ECompEditorPropertyPart *property_part)
{
property_part->priv = G_TYPE_INSTANCE_GET_PRIVATE (property_part,
E_TYPE_COMP_EDITOR_PROPERTY_PART,
ECompEditorPropertyPartPrivate);
property_part->priv->visible = TRUE;
property_part->priv->sensitize_handled = FALSE;
}
static void
e_comp_editor_property_part_class_init (ECompEditorPropertyPartClass *klass)
{
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPrivate));
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = e_comp_editor_property_part_set_property;
object_class->get_property = e_comp_editor_property_part_get_property;
object_class->constructed = e_comp_editor_property_part_constructed;
object_class->dispose = e_comp_editor_property_part_dispose;
g_object_class_install_property (
object_class,
PROPERTY_PART_PROP_VISIBLE,
g_param_spec_boolean (
"visible",
"Visible",
"Whether the part is visible",
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
PROPERTY_PART_PROP_SENSITIZE_HANDLED,
g_param_spec_boolean (
"sensitize-handled",
"Sensitize Handled",
"Whether the part's sensitive property is handled by the owner of it",
FALSE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
property_part_signals[PROPERTY_PART_CHANGED] = g_signal_new (
"changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (ECompEditorPropertyPartClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0,
G_TYPE_NONE);
}
gboolean
e_comp_editor_property_part_get_visible (ECompEditorPropertyPart *property_part)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), FALSE);
return property_part->priv->visible;
}
void
e_comp_editor_property_part_set_visible (ECompEditorPropertyPart *property_part,
gboolean visible)
{
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
if ((property_part->priv->visible ? 1 : 0) == (visible ? 1 : 0))
return;
property_part->priv->visible = visible;
g_object_notify (G_OBJECT (property_part), "visible");
}
gboolean
e_comp_editor_property_part_get_sensitize_handled (ECompEditorPropertyPart *property_part)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), FALSE);
return property_part->priv->sensitize_handled;
}
void
e_comp_editor_property_part_set_sensitize_handled (ECompEditorPropertyPart *property_part,
gboolean sensitize_handled)
{
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
if ((property_part->priv->sensitize_handled ? 1 : 0) == (sensitize_handled ? 1 : 0))
return;
property_part->priv->sensitize_handled = sensitize_handled;
g_object_notify (G_OBJECT (property_part), "sensitize-handled");
}
void
e_comp_editor_property_part_create_widgets (ECompEditorPropertyPart *property_part,
GtkWidget **out_label_widget,
GtkWidget **out_edit_widget)
{
ECompEditorPropertyPartClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
g_return_if_fail (property_part->priv->label_widget == NULL);
g_return_if_fail (property_part->priv->edit_widget == NULL);
klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->create_widgets != NULL);
klass->create_widgets (property_part, out_label_widget, out_edit_widget);
}
GtkWidget *
e_comp_editor_property_part_get_label_widget (ECompEditorPropertyPart *property_part)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), NULL);
return property_part->priv->label_widget;
}
GtkWidget *
e_comp_editor_property_part_get_edit_widget (ECompEditorPropertyPart *property_part)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part), NULL);
return property_part->priv->edit_widget;
}
void
e_comp_editor_property_part_fill_widget (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->fill_widget != NULL);
klass->fill_widget (property_part, component);
}
void
e_comp_editor_property_part_fill_component (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
klass = E_COMP_EDITOR_PROPERTY_PART_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->fill_component != NULL);
klass->fill_component (property_part, component);
}
void
e_comp_editor_property_part_emit_changed (ECompEditorPropertyPart *property_part)
{
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART (property_part));
g_signal_emit (property_part, property_part_signals[PROPERTY_PART_CHANGED], 0, NULL);
}
/* ************************************************************************* */
struct _ECompEditorPropertyPartStringPrivate {
gboolean is_multivalue;
};
G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartString, e_comp_editor_property_part_string, E_TYPE_COMP_EDITOR_PROPERTY_PART)
static void
ecepp_string_create_widgets (ECompEditorPropertyPart *property_part,
GtkWidget **out_label_widget,
GtkWidget **out_edit_widget)
{
ECompEditorPropertyPartStringClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
g_return_if_fail (out_label_widget != NULL);
g_return_if_fail (out_edit_widget != NULL);
klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (g_type_is_a (klass->entry_type, GTK_TYPE_ENTRY) ||
g_type_is_a (klass->entry_type, GTK_TYPE_TEXT_VIEW));
/* The descendant sets the 'out_label_widget' parameter */
*out_edit_widget = g_object_new (klass->entry_type, NULL);
g_return_if_fail (*out_edit_widget != NULL);
g_object_set (G_OBJECT (*out_edit_widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_widget_show (*out_edit_widget);
if (g_type_is_a (klass->entry_type, GTK_TYPE_TEXT_VIEW)) {
GtkScrolledWindow *scrolled_window;
GtkTextBuffer *text_buffer;
scrolled_window = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (scrolled_window, GTK_SHADOW_IN);
gtk_widget_show (GTK_WIDGET (scrolled_window));
gtk_container_add (GTK_CONTAINER (scrolled_window), *out_edit_widget);
g_object_set (G_OBJECT (*out_edit_widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", TRUE,
"valign", GTK_ALIGN_FILL,
NULL);
g_object_set (G_OBJECT (scrolled_window),
"hexpand", FALSE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (*out_edit_widget));
g_signal_connect_swapped (text_buffer, "changed",
G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
*out_edit_widget = GTK_WIDGET (scrolled_window);
} else {
g_signal_connect_swapped (*out_edit_widget, "changed",
G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
}
}
static void
ecepp_string_fill_widget (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartStringClass *klass;
GtkWidget *edit_widget;
GString *multivalue = NULL;
icalproperty *prop;
const gchar *value = NULL;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (GTK_IS_ENTRY (edit_widget) || GTK_IS_SCROLLED_WINDOW (edit_widget));
klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (klass->ical_get_func != NULL);
if (e_comp_editor_property_part_string_is_multivalue (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part))) {
for (prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
prop;
prop = icalcomponent_get_next_property (component, klass->ical_prop_kind)) {
value = klass->ical_get_func (prop);
if (!value || !*value)
continue;
if (!multivalue)
multivalue = g_string_new ("");
else if (multivalue->len)
g_string_append_c (multivalue, ',');
g_string_append (multivalue, value);
}
if (multivalue)
value = multivalue->str;
else
value = NULL;
} else {
prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
if (prop)
value = klass->ical_get_func (prop);
}
if (!value)
value = "";
if (GTK_IS_ENTRY (edit_widget)) {
gtk_entry_set_text (GTK_ENTRY (edit_widget), value);
} else /* if (GTK_IS_SCROLLED_WINDOW (edit_widget)) */ {
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (edit_widget))));
gtk_text_buffer_set_text (buffer, value, -1);
}
e_widget_undo_reset (edit_widget);
if (multivalue)
g_string_free (multivalue, TRUE);
}
static void
ecepp_string_fill_component (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartStringClass *klass;
GtkWidget *edit_widget;
icalproperty *prop;
gchar *value;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (GTK_IS_ENTRY (edit_widget) || GTK_IS_SCROLLED_WINDOW (edit_widget));
klass = E_COMP_EDITOR_PROPERTY_PART_STRING_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (klass->ical_new_func != NULL);
g_return_if_fail (klass->ical_set_func != NULL);
if (GTK_IS_ENTRY (edit_widget)) {
value = g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_widget)));
} else /* if (GTK_IS_SCROLLED_WINDOW (edit_widget)) */ {
GtkTextBuffer *buffer;
GtkTextIter text_iter_start, text_iter_end;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (edit_widget))));
gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
}
if (e_comp_editor_property_part_string_is_multivalue (E_COMP_EDITOR_PROPERTY_PART_STRING (property_part))) {
/* Clear all multivalues first */
while (prop = icalcomponent_get_first_property (component, klass->ical_prop_kind), prop) {
icalcomponent_remove_property (component, prop);
icalproperty_free (prop);
}
}
prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
if (value && *value) {
if (prop) {
klass->ical_set_func (prop, value);
} else {
prop = klass->ical_new_func (value);
icalcomponent_add_property (component, prop);
}
} else if (prop) {
icalcomponent_remove_property (component, prop);
icalproperty_free (prop);
}
g_free (value);
}
static void
e_comp_editor_property_part_string_init (ECompEditorPropertyPartString *part_string)
{
part_string->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_string,
E_TYPE_COMP_EDITOR_PROPERTY_PART_STRING,
ECompEditorPropertyPartStringPrivate);
part_string->priv->is_multivalue = FALSE;
}
static void
e_comp_editor_property_part_string_class_init (ECompEditorPropertyPartStringClass *klass)
{
ECompEditorPropertyPartClass *part_class;
g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartStringPrivate));
klass->entry_type = GTK_TYPE_ENTRY;
klass->ical_prop_kind = ICAL_NO_PROPERTY;
klass->ical_new_func = NULL;
klass->ical_set_func = NULL;
klass->ical_get_func = NULL;
part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
part_class->create_widgets = ecepp_string_create_widgets;
part_class->fill_widget = ecepp_string_fill_widget;
part_class->fill_component = ecepp_string_fill_component;
}
void
e_comp_editor_property_part_string_attach_focus_tracker (ECompEditorPropertyPartString *part_string,
EFocusTracker *focus_tracker)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string));
if (!focus_tracker)
return;
g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_string));
if (edit_widget) {
if (GTK_IS_SCROLLED_WINDOW (edit_widget))
e_widget_undo_attach (gtk_bin_get_child (GTK_BIN (edit_widget)), focus_tracker);
else
e_widget_undo_attach (edit_widget, focus_tracker);
}
}
void
e_comp_editor_property_part_string_set_is_multivalue (ECompEditorPropertyPartString *part_string,
gboolean is_multivalue)
{
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string));
part_string->priv->is_multivalue = is_multivalue;
}
gboolean
e_comp_editor_property_part_string_is_multivalue (ECompEditorPropertyPartString *part_string)
{
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_STRING (part_string), FALSE);
return part_string->priv->is_multivalue;
}
/* ************************************************************************* */
struct _ECompEditorPropertyPartDatetimePrivate {
GWeakRef timezone_entry;
};
G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartDatetime, e_comp_editor_property_part_datetime, E_TYPE_COMP_EDITOR_PROPERTY_PART)
static void
ecepp_datetime_changed_cb (ECompEditorPropertyPart *property_part)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
if (!edit_widget || e_date_edit_has_focus (E_DATE_EDIT (edit_widget)) ||
!e_date_edit_date_is_valid (E_DATE_EDIT (edit_widget)) ||
!e_date_edit_time_is_valid (E_DATE_EDIT (edit_widget)))
return;
e_comp_editor_property_part_emit_changed (property_part);
}
static void
ecepp_datetime_create_widgets (ECompEditorPropertyPart *property_part,
GtkWidget **out_label_widget,
GtkWidget **out_edit_widget)
{
ECompEditorPropertyPartDatetimeClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
g_return_if_fail (out_label_widget != NULL);
g_return_if_fail (out_edit_widget != NULL);
klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
/* The descendant sets the 'out_label_widget' parameter */
*out_edit_widget = e_date_edit_new ();
g_return_if_fail (*out_edit_widget != NULL);
g_object_set (G_OBJECT (*out_edit_widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_START,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_widget_show (*out_edit_widget);
g_signal_connect_swapped (*out_edit_widget, "changed",
G_CALLBACK (ecepp_datetime_changed_cb), property_part);
g_signal_connect_swapped (*out_edit_widget, "notify::show-time",
G_CALLBACK (ecepp_datetime_changed_cb), property_part);
}
static void
ecepp_datetime_fill_widget (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartDatetime *part_datetime;
ECompEditorPropertyPartDatetimeClass *klass;
GtkWidget *edit_widget;
icalproperty *prop;
struct icaltimetype value;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (klass->ical_get_func != NULL);
part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part);
prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
if (prop)
value = klass->ical_get_func (prop);
else
value = icaltime_null_time ();
e_comp_editor_property_part_datetime_set_value (part_datetime, value);
}
static void
ecepp_datetime_fill_component (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartDatetime *part_datetime;
ECompEditorPropertyPartDatetimeClass *klass;
GtkWidget *edit_widget;
EDateEdit *date_edit;
icalproperty *prop;
struct icaltimetype value;
time_t tt;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
klass = E_COMP_EDITOR_PROPERTY_PART_DATETIME_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (klass->ical_new_func != NULL);
g_return_if_fail (klass->ical_set_func != NULL);
part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (property_part);
date_edit = E_DATE_EDIT (edit_widget);
tt = e_date_edit_get_time (date_edit);
prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
if (e_date_edit_get_allow_no_date_set (date_edit) && tt == (time_t) -1) {
if (prop) {
icalcomponent_remove_property (component, prop);
icalproperty_free (prop);
}
} else {
value = e_comp_editor_property_part_datetime_get_value (part_datetime);
if (prop) {
klass->ical_set_func (prop, value);
cal_comp_util_update_tzid_parameter (prop, value);
} else {
prop = klass->ical_new_func (value);
cal_comp_util_update_tzid_parameter (prop, value);
icalcomponent_add_property (component, prop);
}
}
}
static void
ecepp_datetime_finalize (GObject *object)
{
ECompEditorPropertyPartDatetime *part_datetime = E_COMP_EDITOR_PROPERTY_PART_DATETIME (object);
g_weak_ref_clear (&part_datetime->priv->timezone_entry);
G_OBJECT_CLASS (e_comp_editor_property_part_datetime_parent_class)->finalize (object);
}
static void
e_comp_editor_property_part_datetime_init (ECompEditorPropertyPartDatetime *part_datetime)
{
part_datetime->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_datetime,
E_TYPE_COMP_EDITOR_PROPERTY_PART_DATETIME,
ECompEditorPropertyPartDatetimePrivate);
g_weak_ref_init (&part_datetime->priv->timezone_entry, NULL);
}
static void
e_comp_editor_property_part_datetime_class_init (ECompEditorPropertyPartDatetimeClass *klass)
{
ECompEditorPropertyPartClass *part_class;
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartDatetimePrivate));
klass->ical_prop_kind = ICAL_NO_PROPERTY;
klass->ical_new_func = NULL;
klass->ical_set_func = NULL;
klass->ical_get_func = NULL;
part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
part_class->create_widgets = ecepp_datetime_create_widgets;
part_class->fill_widget = ecepp_datetime_fill_widget;
part_class->fill_component = ecepp_datetime_fill_component;
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = ecepp_datetime_finalize;
}
void
e_comp_editor_property_part_datetime_attach_timezone_entry (ECompEditorPropertyPartDatetime *part_datetime,
ETimezoneEntry *timezone_entry)
{
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
if (timezone_entry)
g_return_if_fail (E_IS_TIMEZONE_ENTRY (timezone_entry));
g_weak_ref_set (&part_datetime->priv->timezone_entry, timezone_entry);
}
void
e_comp_editor_property_part_datetime_set_date_only (ECompEditorPropertyPartDatetime *part_datetime,
gboolean date_only)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
if ((e_date_edit_get_show_time (E_DATE_EDIT (edit_widget)) ? 1 : 0) == ((!date_only) ? 1 : 0))
return;
e_date_edit_set_show_time (E_DATE_EDIT (edit_widget), !date_only);
}
gboolean
e_comp_editor_property_part_datetime_get_date_only (ECompEditorPropertyPartDatetime *part_datetime)
{
GtkWidget *edit_widget;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
return !e_date_edit_get_show_time (E_DATE_EDIT (edit_widget));
}
void
e_comp_editor_property_part_datetime_set_allow_no_date_set (ECompEditorPropertyPartDatetime *part_datetime,
gboolean allow_no_date_set)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
e_date_edit_set_allow_no_date_set (E_DATE_EDIT (edit_widget), allow_no_date_set);
}
gboolean
e_comp_editor_property_part_datetime_get_allow_no_date_set (ECompEditorPropertyPartDatetime *part_datetime)
{
GtkWidget *edit_widget;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
return !e_date_edit_get_allow_no_date_set (E_DATE_EDIT (edit_widget));
}
void
e_comp_editor_property_part_datetime_set_value (ECompEditorPropertyPartDatetime *part_datetime,
struct icaltimetype value)
{
GtkWidget *edit_widget;
EDateEdit *date_edit;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime));
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_if_fail (E_IS_DATE_EDIT (edit_widget));
date_edit = E_DATE_EDIT (edit_widget);
if (!e_date_edit_get_allow_no_date_set (date_edit) && (icaltime_is_null_time (value) ||
!icaltime_is_valid_time (value))) {
value = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
}
if (icaltime_is_null_time (value) ||
!icaltime_is_valid_time (value)) {
e_date_edit_set_time (date_edit, (time_t) -1);
} else {
e_date_edit_set_date (date_edit, value.year, value.month, value.day);
if (!value.is_date)
e_date_edit_set_time_of_day (date_edit, value.hour, value.minute);
else if (e_date_edit_get_show_time (date_edit))
e_date_edit_set_time_of_day (date_edit, 0, 0);
else if (e_date_edit_get_allow_no_date_set (date_edit))
e_date_edit_set_time_of_day (date_edit, -1, -1);
e_comp_editor_property_part_datetime_set_date_only (part_datetime, value.is_date);
}
}
struct icaltimetype
e_comp_editor_property_part_datetime_get_value (ECompEditorPropertyPartDatetime *part_datetime)
{
ETimezoneEntry *timezone_entry = NULL;
GtkWidget *edit_widget;
EDateEdit *date_edit;
struct icaltimetype value = icaltime_null_time ();
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), value);
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), value);
date_edit = E_DATE_EDIT (edit_widget);
if (!e_date_edit_get_date (date_edit, &value.year, &value.month, &value.day))
return icaltime_null_time ();
if (!e_date_edit_get_show_time (date_edit)) {
value.is_date = 1;
} else {
value.zone = NULL;
value.is_date = !e_date_edit_get_time_of_day (date_edit, &value.hour, &value.minute);
if (!value.is_date) {
timezone_entry = g_weak_ref_get (&part_datetime->priv->timezone_entry);
if (timezone_entry)
value.zone = e_timezone_entry_get_timezone (timezone_entry);
if (!value.zone)
value.zone = icaltimezone_get_utc_timezone ();
}
}
g_clear_object (&timezone_entry);
return value;
}
gboolean
e_comp_editor_property_part_datetime_check_validity (ECompEditorPropertyPartDatetime *part_datetime,
gboolean *out_date_is_valid,
gboolean *out_time_is_valid)
{
GtkWidget *edit_widget;
EDateEdit *date_edit;
gboolean date_is_valid = TRUE, time_is_valid = TRUE;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (part_datetime), FALSE);
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_datetime));
g_return_val_if_fail (E_IS_DATE_EDIT (edit_widget), FALSE);
date_edit = E_DATE_EDIT (edit_widget);
if (!e_date_edit_get_allow_no_date_set (date_edit) ||
e_date_edit_get_time (date_edit) != (time_t) -1) {
date_is_valid = e_date_edit_date_is_valid (date_edit);
if (e_date_edit_get_show_time (date_edit))
time_is_valid = e_date_edit_time_is_valid (date_edit);
}
if (out_date_is_valid)
*out_date_is_valid = date_is_valid;
if (out_time_is_valid)
*out_time_is_valid = time_is_valid;
return date_is_valid && time_is_valid;
}
/* ************************************************************************* */
struct _ECompEditorPropertyPartSpinPrivate {
gint dummy;
};
G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartSpin, e_comp_editor_property_part_spin, E_TYPE_COMP_EDITOR_PROPERTY_PART)
static void
ecepp_spin_create_widgets (ECompEditorPropertyPart *property_part,
GtkWidget **out_label_widget,
GtkWidget **out_edit_widget)
{
ECompEditorPropertyPartSpinClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
g_return_if_fail (out_label_widget != NULL);
g_return_if_fail (out_edit_widget != NULL);
klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
/* The descendant sets the 'out_label_widget' parameter */
*out_edit_widget = gtk_spin_button_new_with_range (-10, 10, 1);
g_return_if_fail (*out_edit_widget != NULL);
g_object_set (G_OBJECT (*out_edit_widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (*out_edit_widget), 0);
gtk_widget_show (*out_edit_widget);
g_signal_connect_swapped (*out_edit_widget, "value-changed",
G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
}
static void
ecepp_spin_fill_widget (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartSpinClass *klass;
GtkWidget *edit_widget;
icalproperty *prop;
gint value;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (klass->ical_get_func != NULL);
prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
if (prop) {
value = klass->ical_get_func (prop);
} else {
gdouble d_min, d_max;
gtk_spin_button_get_range (GTK_SPIN_BUTTON (edit_widget), &d_min, &d_max);
value = (gint) d_min;
}
gtk_spin_button_set_value (GTK_SPIN_BUTTON (edit_widget), value);
}
static void
ecepp_spin_fill_component (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
ECompEditorPropertyPartSpinClass *klass;
GtkWidget *edit_widget;
icalproperty *prop;
gint value;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
klass = E_COMP_EDITOR_PROPERTY_PART_SPIN_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (klass->ical_new_func != NULL);
g_return_if_fail (klass->ical_set_func != NULL);
value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (edit_widget));
prop = icalcomponent_get_first_property (component, klass->ical_prop_kind);
if (prop) {
klass->ical_set_func (prop, value);
} else {
prop = klass->ical_new_func (value);
icalcomponent_add_property (component, prop);
}
}
static void
e_comp_editor_property_part_spin_init (ECompEditorPropertyPartSpin *part_spin)
{
part_spin->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_spin,
E_TYPE_COMP_EDITOR_PROPERTY_PART_SPIN,
ECompEditorPropertyPartSpinPrivate);
}
static void
e_comp_editor_property_part_spin_class_init (ECompEditorPropertyPartSpinClass *klass)
{
ECompEditorPropertyPartClass *part_class;
g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartSpinPrivate));
klass->ical_prop_kind = ICAL_NO_PROPERTY;
klass->ical_new_func = NULL;
klass->ical_set_func = NULL;
klass->ical_get_func = NULL;
part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
part_class->create_widgets = ecepp_spin_create_widgets;
part_class->fill_widget = ecepp_spin_fill_widget;
part_class->fill_component = ecepp_spin_fill_component;
}
void
e_comp_editor_property_part_spin_set_range (ECompEditorPropertyPartSpin *part_spin,
gint min_value,
gint max_value)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (part_spin));
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_spin));
g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
gtk_spin_button_set_range (GTK_SPIN_BUTTON (edit_widget), min_value, max_value);
}
void
e_comp_editor_property_part_spin_get_range (ECompEditorPropertyPartSpin *part_spin,
gint *out_min_value,
gint *out_max_value)
{
GtkWidget *edit_widget;
gdouble d_min = 0, d_max = 0;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_SPIN (part_spin));
edit_widget = e_comp_editor_property_part_get_edit_widget (E_COMP_EDITOR_PROPERTY_PART (part_spin));
g_return_if_fail (GTK_IS_SPIN_BUTTON (edit_widget));
gtk_spin_button_get_range (GTK_SPIN_BUTTON (edit_widget), &d_min, &d_max);
if (out_min_value)
*out_min_value = (gint) d_min;
if (out_max_value)
*out_max_value = (gint) d_max;
}
/* ************************************************************************* */
struct _ECompEditorPropertyPartPickerPrivate {
gint dummy;
};
G_DEFINE_ABSTRACT_TYPE (ECompEditorPropertyPartPicker, e_comp_editor_property_part_picker, E_TYPE_COMP_EDITOR_PROPERTY_PART)
static void
ecepp_picker_create_widgets (ECompEditorPropertyPart *property_part,
GtkWidget **out_label_widget,
GtkWidget **out_edit_widget)
{
ECompEditorPropertyPartPickerClass *klass;
GtkComboBoxText *combo_box;
GSList *ids = NULL, *display_names = NULL, *i_link, *dn_link;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
g_return_if_fail (out_label_widget != NULL);
g_return_if_fail (out_edit_widget != NULL);
klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (property_part);
g_return_if_fail (klass != NULL);
/* The descendant sets the 'out_label_widget' parameter */
*out_edit_widget = gtk_combo_box_text_new ();
g_return_if_fail (*out_edit_widget != NULL);
g_object_set (G_OBJECT (*out_edit_widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_widget_show (*out_edit_widget);
e_comp_editor_property_part_picker_get_values (E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
&ids, &display_names);
g_warn_if_fail (g_slist_length (ids) == g_slist_length (display_names));
combo_box = GTK_COMBO_BOX_TEXT (*out_edit_widget);
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)) {
const gchar *id, *display_name;
id = i_link->data;
display_name = dn_link->data;
g_warn_if_fail (id != NULL);
g_warn_if_fail (display_name != NULL);
if (!id || !display_name)
continue;
gtk_combo_box_text_append (combo_box, id, display_name);
}
g_slist_free_full (ids, g_free);
g_slist_free_full (display_names, g_free);
g_signal_connect_swapped (*out_edit_widget, "changed",
G_CALLBACK (e_comp_editor_property_part_emit_changed), property_part);
}
static void
ecepp_picker_fill_widget (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
GtkWidget *edit_widget;
gchar *id = NULL;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
if (e_comp_editor_property_part_picker_get_from_component (
E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
component, &id) && id) {
gtk_combo_box_set_active_id (GTK_COMBO_BOX (edit_widget), id);
g_free (id);
} else {
gtk_combo_box_set_active (GTK_COMBO_BOX (edit_widget), 0);
}
}
static void
ecepp_picker_fill_component (ECompEditorPropertyPart *property_part,
icalcomponent *component)
{
GtkWidget *edit_widget;
const gchar *id;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (property_part));
g_return_if_fail (component != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (property_part);
g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (edit_widget));
g_return_if_fail (id != NULL);
e_comp_editor_property_part_picker_set_to_component (
E_COMP_EDITOR_PROPERTY_PART_PICKER (property_part),
id, component);
}
static void
e_comp_editor_property_part_picker_init (ECompEditorPropertyPartPicker *part_picker)
{
part_picker->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_picker,
E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER,
ECompEditorPropertyPartPickerPrivate);
}
static void
e_comp_editor_property_part_picker_class_init (ECompEditorPropertyPartPickerClass *klass)
{
ECompEditorPropertyPartClass *part_class;
g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPickerPrivate));
part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
part_class->create_widgets = ecepp_picker_create_widgets;
part_class->fill_widget = ecepp_picker_fill_widget;
part_class->fill_component = ecepp_picker_fill_component;
}
/* Both out_ids and out_display_names contain newly allocated strings,
where also n-th element of out_uids corresponds to n-th element of
the out_display_names. */
void
e_comp_editor_property_part_picker_get_values (ECompEditorPropertyPartPicker *part_picker,
GSList **out_ids,
GSList **out_display_names)
{
ECompEditorPropertyPartPickerClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->get_values != NULL);
klass->get_values (part_picker, out_ids, out_display_names);
}
gboolean
e_comp_editor_property_part_picker_get_from_component (ECompEditorPropertyPartPicker *part_picker,
icalcomponent *component,
gchar **out_id)
{
ECompEditorPropertyPartPickerClass *klass;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker), FALSE);
klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
g_return_val_if_fail (klass != NULL, FALSE);
g_return_val_if_fail (klass->get_from_component != NULL, FALSE);
return klass->get_from_component (part_picker, component, out_id);
}
void
e_comp_editor_property_part_picker_set_to_component (ECompEditorPropertyPartPicker *part_picker,
const gchar *id,
icalcomponent *component)
{
ECompEditorPropertyPartPickerClass *klass;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
klass = E_COMP_EDITOR_PROPERTY_PART_PICKER_GET_CLASS (part_picker);
g_return_if_fail (klass != NULL);
g_return_if_fail (klass->set_to_component != NULL);
klass->set_to_component (part_picker, id, component);
}
const gchar *
e_comp_editor_property_part_picker_get_selected_id (ECompEditorPropertyPartPicker *part_picker)
{
GtkWidget *edit_widget;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker), NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (
E_COMP_EDITOR_PROPERTY_PART (part_picker));
g_return_val_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget), NULL);
return gtk_combo_box_get_active_id (GTK_COMBO_BOX (edit_widget));
}
void
e_comp_editor_property_part_picker_set_selected_id (ECompEditorPropertyPartPicker *part_picker,
const gchar *id)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker));
g_return_if_fail (id != NULL);
edit_widget = e_comp_editor_property_part_get_edit_widget (
E_COMP_EDITOR_PROPERTY_PART (part_picker));
g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (edit_widget));
gtk_combo_box_set_active_id (GTK_COMBO_BOX (edit_widget), id);
}
/* ************************************************************************* */
struct _ECompEditorPropertyPartPickerWithMapPrivate {
ECompEditorPropertyPartPickerMap *map;
gint n_map_elems;
gchar *label;
icalproperty_kind ical_prop_kind;
ECompEditorPropertyPartPickerMapICalNewFunc ical_new_func;
ECompEditorPropertyPartPickerMapICalSetFunc ical_set_func;
ECompEditorPropertyPartPickerMapICalGetFunc ical_get_func;
};
enum {
PICKER_WITH_MAP_PROP_0,
PICKER_WITH_MAP_PROP_MAP,
PICKER_WITH_MAP_PROP_LABEL
};
G_DEFINE_TYPE (ECompEditorPropertyPartPickerWithMap, e_comp_editor_property_part_picker_with_map, E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER)
static void
ecepp_picker_with_map_get_values (ECompEditorPropertyPartPicker *part_picker,
GSList **out_ids,
GSList **out_display_names)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
gint ii;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker));
g_return_if_fail (out_ids != NULL);
g_return_if_fail (out_display_names != NULL);
part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
g_return_if_fail (part_picker_with_map->priv->map != NULL);
g_return_if_fail (part_picker_with_map->priv->n_map_elems > 0);
for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
*out_ids = g_slist_prepend (*out_ids, g_strdup_printf ("%d", ii));
*out_display_names = g_slist_prepend (*out_display_names,
g_strdup (part_picker_with_map->priv->map[ii].description));
}
*out_ids = g_slist_reverse (*out_ids);
*out_display_names = g_slist_reverse (*out_display_names);
}
static gboolean
ecepp_picker_with_map_get_from_component (ECompEditorPropertyPartPicker *part_picker,
icalcomponent *component,
gchar **out_id)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
icalproperty *prop;
gint ii, value;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker), FALSE);
g_return_val_if_fail (component != NULL, FALSE);
g_return_val_if_fail (out_id != NULL, FALSE);
part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
g_return_val_if_fail (part_picker_with_map->priv->map != NULL, FALSE);
g_return_val_if_fail (part_picker_with_map->priv->n_map_elems > 0, FALSE);
g_return_val_if_fail (part_picker_with_map->priv->ical_prop_kind != ICAL_NO_PROPERTY, FALSE);
g_return_val_if_fail (part_picker_with_map->priv->ical_get_func != NULL, FALSE);
prop = icalcomponent_get_first_property (component, part_picker_with_map->priv->ical_prop_kind);
if (!prop)
return FALSE;
value = part_picker_with_map->priv->ical_get_func (prop);
for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
gboolean matches;
if (part_picker_with_map->priv->map[ii].matches_func) {
matches = part_picker_with_map->priv->map[ii].matches_func (part_picker_with_map->priv->map[ii].value, value);
} else {
matches = value == part_picker_with_map->priv->map[ii].value;
}
if (matches) {
*out_id = g_strdup_printf ("%d", ii);
return TRUE;
}
}
return FALSE;
}
static void
ecepp_picker_with_map_set_to_component (ECompEditorPropertyPartPicker *part_picker,
const gchar *id,
icalcomponent *component)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
icalproperty *prop;
gint ii, value;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker));
g_return_if_fail (id != NULL);
g_return_if_fail (component != NULL);
part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker);
g_return_if_fail (part_picker_with_map->priv->map != NULL);
g_return_if_fail (part_picker_with_map->priv->n_map_elems > 0);
g_return_if_fail (part_picker_with_map->priv->ical_prop_kind != ICAL_NO_PROPERTY);
g_return_if_fail (part_picker_with_map->priv->ical_new_func != NULL);
g_return_if_fail (part_picker_with_map->priv->ical_set_func != NULL);
ii = (gint) g_ascii_strtoll (id, NULL, 10);
g_return_if_fail (ii >= 0 && ii < part_picker_with_map->priv->n_map_elems);
prop = icalcomponent_get_first_property (component, part_picker_with_map->priv->ical_prop_kind);
value = part_picker_with_map->priv->map[ii].value;
if (part_picker_with_map->priv->map[ii].delete_prop) {
if (prop) {
icalcomponent_remove_property (component, prop);
icalproperty_free (prop);
}
} else if (prop) {
part_picker_with_map->priv->ical_set_func (prop, value);
} else {
prop = part_picker_with_map->priv->ical_new_func (value);
icalcomponent_add_property (component, prop);
}
}
static void
ecepp_picker_with_map_create_widgets (ECompEditorPropertyPart *property_part,
GtkWidget **out_label_widget,
GtkWidget **out_edit_widget)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
ECompEditorPropertyPartClass *part_class;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part));
g_return_if_fail (out_label_widget != NULL);
g_return_if_fail (out_edit_widget != NULL);
part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_picker_with_map_parent_class);
g_return_if_fail (part_class != NULL);
g_return_if_fail (part_class->create_widgets != NULL);
*out_label_widget = NULL;
part_class->create_widgets (property_part, out_label_widget, out_edit_widget);
g_return_if_fail (*out_label_widget == NULL);
g_return_if_fail (*out_edit_widget != NULL);
part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part);
*out_label_widget = gtk_label_new_with_mnemonic (part_picker_with_map->priv->label);
gtk_label_set_mnemonic_widget (GTK_LABEL (*out_label_widget), *out_edit_widget);
g_object_set (G_OBJECT (*out_label_widget),
"hexpand", FALSE,
"halign", GTK_ALIGN_END,
"vexpand", FALSE,
"valign", GTK_ALIGN_CENTER,
NULL);
gtk_widget_show (*out_label_widget);
}
static void
ecepp_picker_with_map_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
gint ii;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object));
part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object);
switch (property_id) {
case PICKER_WITH_MAP_PROP_MAP:
g_return_if_fail (part_picker_with_map->priv->map == NULL);
part_picker_with_map->priv->map = g_value_get_pointer (value);
for (ii = 0; part_picker_with_map->priv->map[ii].description; ii++) {
/* pre-count elements */
}
part_picker_with_map->priv->n_map_elems = ii;
return;
case PICKER_WITH_MAP_PROP_LABEL:
g_free (part_picker_with_map->priv->label);
part_picker_with_map->priv->label = g_value_dup_string (value);
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
ecepp_picker_with_map_finalize (GObject *object)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map =
E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (object);
if (part_picker_with_map->priv->map && part_picker_with_map->priv->n_map_elems > 0) {
gint ii;
for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
g_free ((gchar *) part_picker_with_map->priv->map[ii].description);
}
g_free (part_picker_with_map->priv->map);
part_picker_with_map->priv->map = NULL;
}
g_free (part_picker_with_map->priv->label);
part_picker_with_map->priv->label = NULL;
G_OBJECT_CLASS (e_comp_editor_property_part_picker_with_map_parent_class)->finalize (object);
}
static void
e_comp_editor_property_part_picker_with_map_init (ECompEditorPropertyPartPickerWithMap *part_picker_with_map)
{
part_picker_with_map->priv = G_TYPE_INSTANCE_GET_PRIVATE (part_picker_with_map,
E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP,
ECompEditorPropertyPartPickerWithMapPrivate);
}
static void
e_comp_editor_property_part_picker_with_map_class_init (ECompEditorPropertyPartPickerWithMapClass *klass)
{
ECompEditorPropertyPartPickerClass *part_picker_class;
ECompEditorPropertyPartClass *part_class;
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (ECompEditorPropertyPartPickerWithMapPrivate));
part_picker_class = E_COMP_EDITOR_PROPERTY_PART_PICKER_CLASS (klass);
part_picker_class->get_values = ecepp_picker_with_map_get_values;
part_picker_class->get_from_component = ecepp_picker_with_map_get_from_component;
part_picker_class->set_to_component = ecepp_picker_with_map_set_to_component;
part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
part_class->create_widgets = ecepp_picker_with_map_create_widgets;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = ecepp_picker_with_map_set_property;
object_class->finalize = ecepp_picker_with_map_finalize;
g_object_class_install_property (
object_class,
PICKER_WITH_MAP_PROP_MAP,
g_param_spec_pointer (
"map",
"Map",
"Map of values, .description-NULL-terminated",
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
PICKER_WITH_MAP_PROP_LABEL,
g_param_spec_string (
"label",
"Label",
"Label of the picker",
NULL,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
ECompEditorPropertyPart *
e_comp_editor_property_part_picker_with_map_new (const ECompEditorPropertyPartPickerMap map[],
gint n_map_elements,
const gchar *label,
icalproperty_kind ical_prop_kind,
ECompEditorPropertyPartPickerMapICalNewFunc ical_new_func,
ECompEditorPropertyPartPickerMapICalSetFunc ical_set_func,
ECompEditorPropertyPartPickerMapICalGetFunc ical_get_func)
{
ECompEditorPropertyPartPickerWithMap *part_picker_with_map;
ECompEditorPropertyPartPickerMap *map_copy;
ECompEditorPropertyPart *property_part;
gint ii;
g_return_val_if_fail (map != NULL, NULL);
g_return_val_if_fail (n_map_elements > 0, NULL);
g_return_val_if_fail (label != NULL, NULL);
g_return_val_if_fail (ical_prop_kind != ICAL_NO_PROPERTY, NULL);
g_return_val_if_fail (ical_new_func != NULL, NULL);
g_return_val_if_fail (ical_set_func != NULL, NULL);
g_return_val_if_fail (ical_get_func != NULL, NULL);
map_copy = g_new0 (ECompEditorPropertyPartPickerMap, n_map_elements + 1);
for (ii = 0; ii < n_map_elements; ii++) {
map_copy[ii] = map[ii];
map_copy[ii].description = g_strdup (map[ii].description);
}
property_part = g_object_new (E_TYPE_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP,
"map", map_copy,
"label", label,
NULL);
part_picker_with_map = E_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (property_part);
part_picker_with_map->priv->ical_prop_kind = ical_prop_kind;
part_picker_with_map->priv->ical_new_func = ical_new_func;
part_picker_with_map->priv->ical_set_func = ical_set_func;
part_picker_with_map->priv->ical_get_func = ical_get_func;
return property_part;
}
gint
e_comp_editor_property_part_picker_with_map_get_selected (ECompEditorPropertyPartPickerWithMap *part_picker_with_map)
{
gint ii;
const gchar *id;
g_return_val_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker_with_map), -1);
g_return_val_if_fail (part_picker_with_map->priv->map != NULL, -1);
id = e_comp_editor_property_part_picker_get_selected_id (E_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker_with_map));
if (!id)
return -1;
ii = (gint) g_ascii_strtoll (id, NULL, 10);
if (ii < 0 || ii >= part_picker_with_map->priv->n_map_elems)
return -1;
return part_picker_with_map->priv->map[ii].value;
}
void
e_comp_editor_property_part_picker_with_map_set_selected (ECompEditorPropertyPartPickerWithMap *part_picker_with_map,
gint value)
{
gint ii;
g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_PICKER_WITH_MAP (part_picker_with_map));
g_return_if_fail (part_picker_with_map->priv->map != NULL);
for (ii = 0; ii < part_picker_with_map->priv->n_map_elems; ii++) {
if (part_picker_with_map->priv->map[ii].value == value) {
gchar *id;
id = g_strdup_printf ("%d", ii);
e_comp_editor_property_part_picker_set_selected_id (
E_COMP_EDITOR_PROPERTY_PART_PICKER (part_picker_with_map), id);
g_free (id);
return;
}
}
g_warn_if_reached ();
}
/* ************************************************************************* */