diff options
Diffstat (limited to 'e-util')
-rw-r--r-- | e-util/Makefile.am | 4 | ||||
-rw-r--r-- | e-util/e-plugin-util.c | 462 | ||||
-rw-r--r-- | e-util/e-plugin-util.h | 46 |
3 files changed, 511 insertions, 1 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 8a15c521f6..b34e0375a8 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -39,6 +39,7 @@ eutilinclude_HEADERS = \ e-print.h \ e-plugin.h \ e-plugin-ui.h \ + e-plugin-util.h \ e-profile-event.h \ e-selection.h \ e-signature.h \ @@ -112,8 +113,9 @@ libeutil_la_SOURCES = \ e-mktemp.c \ e-module.c \ e-non-intrusive-error-dialog.c \ - e-plugin-ui.c \ e-plugin.c \ + e-plugin-ui.c \ + e-plugin-util.c \ e-print.c \ e-profile-event.c \ e-selection.c \ diff --git a/e-util/e-plugin-util.c b/e-util/e-plugin-util.c new file mode 100644 index 0000000000..885d017e15 --- /dev/null +++ b/e-util/e-plugin-util.c @@ -0,0 +1,462 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2010 Novell, Inc. (www.novell.com) + */ + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <libsoup/soup.h> +#include <libedataserver/e-source.h> +#include <string.h> + +#include "e-plugin-util.h" + +/* name of a property on a widget with corresponding property name for an ESource */ +#define EPU_SP_NAME "e-source-property-name" + +#define EPU_CHECK_TRUE "epu-check-true-value" +#define EPU_CHECK_FALSE "epu-check-false-value" + +static gboolean +epu_is_uri_proto (const gchar *uri, const gchar *protocol) +{ + gboolean res; + + g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (protocol != NULL, FALSE); + + res = uri && g_ascii_strncasecmp (uri, protocol, strlen (protocol)) == 0; + + if (res) + res = strchr (protocol, ':') != NULL || uri[strlen (protocol)] == ':'; + + return res; +} + +/** + * e_plugin_util_is_source_proto: + * @source: #ESource object + * @protocol: protocol to check on, like "http", "https", ... + * + * Returns whether given source's uri is of the given protocol. + **/ +gboolean +e_plugin_util_is_source_proto (ESource *source, const gchar *protocol) +{ + gchar *uri; + gboolean res; + + g_return_val_if_fail (source != NULL, FALSE); + g_return_val_if_fail (E_IS_SOURCE (source), FALSE); + g_return_val_if_fail (protocol != NULL, FALSE); + + uri = e_source_get_uri (source); + res = epu_is_uri_proto (uri, protocol); + g_free (uri); + + return res; +} + +/** + * e_plugin_util_is_group_proto: + * @group: #ESourceGroup object + * @protocol: protocol to check on, like "http", "https", ... + * + * Returns whether given groups' base uri is of the given protocol. + **/ +gboolean +e_plugin_util_is_group_proto (ESourceGroup *group, const gchar *protocol) +{ + g_return_val_if_fail (group != NULL, FALSE); + g_return_val_if_fail (E_IS_SOURCE_GROUP (group), FALSE); + g_return_val_if_fail (protocol != NULL, FALSE); + + return epu_is_uri_proto (e_source_group_peek_base_uri (group), protocol); +} + +/** + * e_plugin_util_replace_at_sign: + * @str: string to work with + * + * Replaces all '@' with '%40' in @str. + * Returns newly allocated string. + **/ +gchar * +e_plugin_util_replace_at_sign (const gchar *str) +{ + gchar *res, *at; + + if (!str) + return NULL; + + res = g_strdup (str); + while (at = strchr (res, '@'), at) { + gchar *tmp = g_malloc0 (sizeof (gchar) * (1 + strlen (res) + 2)); + + strncpy (tmp, res, at - res); + strcat (tmp, "%40"); + strcat (tmp, at + 1); + + g_free (res); + res = tmp; + } + + return res; +} + +/** + * e_plugin_util_uri_no_proto: + * @uri: #SoupURI object + * + * Returns uri encoded as string, without protocol part. + * Returned pointer should be freed with g_free. + **/ +gchar * +e_plugin_util_uri_no_proto (SoupURI *uri) +{ + gchar *full_uri, *uri_noproto; + const gchar *tmp; + + g_return_val_if_fail (uri != NULL, NULL); + + full_uri = soup_uri_to_string (uri, FALSE); + g_return_val_if_fail (full_uri != NULL, NULL); + + tmp = strstr (full_uri, "://"); + if (tmp && tmp < strchr (full_uri, '/')) { + uri_noproto = g_strdup (tmp + 3); + } else { + uri_noproto = full_uri; + full_uri = NULL; + } + + g_free (full_uri); + + return uri_noproto; +} + +static void +epu_update_source_property (ESource *source, GObject *object, const gchar *value) +{ + const gchar *property_name; + + g_return_if_fail (source != NULL); + g_return_if_fail (E_IS_SOURCE (source)); + g_return_if_fail (object != NULL); + g_return_if_fail (G_IS_OBJECT (object)); + + property_name = g_object_get_data (object, EPU_SP_NAME); + g_return_if_fail (property_name != NULL); + + e_source_set_property (source, property_name, value); +} + +static void +epu_entry_changed_cb (GObject *entry, ESource *source) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + epu_update_source_property (source, entry, gtk_entry_get_text (GTK_ENTRY (entry))); +} + +static void +epu_check_toggled_cb (GObject *button, ESource *source) +{ + const gchar *true_value, *false_value; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + true_value = g_object_get_data (button, EPU_CHECK_TRUE); + false_value = g_object_get_data (button, EPU_CHECK_FALSE); + + epu_update_source_property (source, button, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? true_value : false_value); +} + +/** + * e_plugin_util_add_entry: + * @parent: two-columns #GtkTable or #GtkContainer, where to add new entry + * @label: label for the entry; can be NULL for no label + * @source: #ESource object to which tight the entry change; can be NULL for no property binding + * @source_property: source's property name to use for a value; can be NULL for no property binding + * + * Adds a #GtkEntry to the table at the last row or to the container, with a given label. + * The entry will be always at the second column of the table. + * Value of an entry will be prefilled with a property value of the given + * source, and the source will be updated on any change of the entry automatically. + * Entry is shown by default. + * + * Returns pointer to newly added #GtkEntry. + **/ +GtkWidget * +e_plugin_util_add_entry (GtkWidget *parent, const gchar *label, ESource *source, const gchar *source_property) +{ + GtkWidget *entry, *lbl = NULL; + const gchar *value; + gint row = -1; + + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (GTK_IS_TABLE (parent) || GTK_IS_CONTAINER (parent), NULL); + + if (source || source_property) { + g_return_val_if_fail (source != NULL, NULL); + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + g_return_val_if_fail (source_property != NULL, NULL); + g_return_val_if_fail (*source_property != 0, NULL); + } + + if (GTK_IS_TABLE (parent)) + row = GTK_TABLE (parent)->nrows; + + if (label) { + lbl = gtk_label_new_with_mnemonic (label); + gtk_widget_show (lbl); + gtk_misc_set_alignment (GTK_MISC (lbl), 0.0, 0.5); + if (row != -1) + gtk_table_attach (GTK_TABLE (parent), lbl, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); + else + gtk_container_add (GTK_CONTAINER (parent), lbl); + } + + if (source) + value = e_source_get_property (source, source_property); + else + value = NULL; + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_text (GTK_ENTRY (entry), value ? value : ""); + if (row != -1) + gtk_table_attach (GTK_TABLE (parent), entry, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); + else + gtk_container_add (GTK_CONTAINER (parent), entry); + + if (lbl) + gtk_label_set_mnemonic_widget (GTK_LABEL (lbl), entry); + + if (source) { + g_object_set_data_full (G_OBJECT (entry), EPU_SP_NAME, g_strdup (source_property), g_free); + g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (epu_entry_changed_cb), source); + } + + return entry; +} + +/** + * e_plugin_util_add_check: + * @parent: either two-columns #GtkTable or #GtkContainer where to add new check box; or NULL to just create it + * @label: label for the check; cannot be NULL + * @source: #ESource object to which tight the check change; can be NULL for no property binding + * @source_property: source's property name to use for a value; can be NULL for no property binding + * @true_value: what value use for a checked state in a source + * @false_value: what value use for an unchecked state in a source + * + * Adds a #GtkCheckButton to the parent (if provided) at the last row, with a given label. + * The check will be always at the second column of the table. + * Value of a check will be prefilled with a property value of the given + * source, and the source will be updated on any change of the check automatically. + * Check is shown by default. + * + * Returns pointer to newly added #GtkCheckButton. + **/ +GtkWidget * +e_plugin_util_add_check (GtkWidget *parent, const gchar *label, ESource *source, const gchar *source_property, const gchar *true_value, const gchar *false_value) +{ + GtkWidget *check; + const gchar *value; + + g_return_val_if_fail (parent == NULL || GTK_IS_TABLE (parent) || GTK_IS_CONTAINER (parent), NULL); + g_return_val_if_fail (label != NULL, NULL); + + if (source || source_property) { + g_return_val_if_fail (source != NULL, NULL); + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + g_return_val_if_fail (source_property != NULL, NULL); + g_return_val_if_fail (*source_property != 0, NULL); + } + + if (source) + value = e_source_get_property (source, source_property); + else + value = NULL; + + check = gtk_check_button_new_with_mnemonic (label); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), + value && (value == true_value || + (true_value && g_str_equal (value, true_value)) || + (!source && g_str_equal (value, "1")))); + gtk_widget_show (check); + + if (parent && GTK_IS_TABLE (parent)) { + gint row = GTK_TABLE (parent)->nrows; + + gtk_table_attach (GTK_TABLE (parent), check, 1, 2, row , row + 1, GTK_FILL, 0, 0, 0); + } else if (parent) { + gtk_container_add (GTK_CONTAINER (parent), check); + } + + if (source) { + g_object_set_data_full (G_OBJECT (check), EPU_SP_NAME, g_strdup (source_property), g_free); + g_object_set_data_full (G_OBJECT (check), EPU_CHECK_TRUE, g_strdup (true_value), g_free); + g_object_set_data_full (G_OBJECT (check), EPU_CHECK_FALSE, g_strdup (false_value), g_free); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (epu_check_toggled_cb), source); + } + + return check; +} + +static void +epu_update_refresh_value (GtkWidget *spin, GtkWidget *combobox, ESource *source) +{ + gchar *value; + gint setting = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)); + switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combobox))) { + case 0: + /* minutes */ + break; + case 1: + /* hours */ + setting *= 60; + break; + case 2: + /* days */ + setting *= 1440; + break; + case 3: + /* weeks */ + setting *= 10080; + break; + default: + g_warning ("%s: Time unit out of range", G_STRFUNC); + break; + } + + value = g_strdup_printf ("%d", setting); + epu_update_source_property (source, G_OBJECT (spin), value); + g_free (value); +} + +static void +epu_refresh_spin_changed_cb (GtkWidget *spin, ESource *source) +{ + g_return_if_fail (spin != NULL); + g_return_if_fail (GTK_IS_SPIN_BUTTON (spin)); + + epu_update_refresh_value (spin, g_object_get_data (G_OBJECT (spin), "refresh-combo"), source); +} + +static void +epu_refresh_combo_changed_cb (GtkWidget *combobox, ESource *source) +{ + g_return_if_fail (combobox != NULL); + g_return_if_fail (GTK_IS_COMBO_BOX (combobox)); + + epu_update_refresh_value (g_object_get_data (G_OBJECT (combobox), "refresh-spin"), combobox, source); +} + +/** + * e_plugin_util_add_refresh: + * @parent: two-columns #GtkTable where to add new "refresh" setup widgets or NULL to just create an hbox + * @label: label for the widgets; can be NULL, but for parent == NULL is ignored + * @source: #ESource object to which tight the refresh change; cannot be NULL + * @source_property: source's property name to use for a value; cannot be NULL + * + * Adds widgets to setup Refresh interval. The stored value is in minutes. + * Returns pointer to an HBox, which contains two widgets, spin and a combo box. + * Both can be accessed by g_object_get_data with a name "refresh-spin" and "refresh-combo". + **/ +GtkWidget * +e_plugin_util_add_refresh (GtkWidget *parent, const gchar *label, ESource *source, const gchar *source_property) +{ + GtkWidget *lbl = NULL, *hbox, *spin, *combo; + const gchar *value; + gint row = -1, value_num, item_num = 0; + + g_return_val_if_fail (parent == NULL || GTK_IS_TABLE (parent), NULL); + g_return_val_if_fail (source != NULL, NULL); + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + g_return_val_if_fail (source_property != NULL, NULL); + g_return_val_if_fail (*source_property != 0, NULL); + + if (parent) + row = GTK_TABLE (parent)->nrows; + + value = e_source_get_property (source, source_property); + if (!value) { + value = "30"; + e_source_set_property (source, source_property, value); + } + + if (label && parent) { + lbl = gtk_label_new_with_mnemonic (label); + gtk_widget_show (lbl); + gtk_misc_set_alignment (GTK_MISC (lbl), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (parent), lbl, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); + } + + hbox = gtk_hbox_new (FALSE, 6); + gtk_widget_show (hbox); + + spin = gtk_spin_button_new_with_range (0, 100, 1); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + + combo = gtk_combo_box_new_text (); + gtk_widget_show (combo); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("minutes")); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("hours")); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("days")); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("weeks")); + gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, TRUE, 0); + + value_num = value ? atoi (value) : 30; + + if (value_num && !(value_num % 10080)) { + /* weeks */ + item_num = 3; + value_num /= 10080; + } else if (value_num && !(value_num % 1440)) { + /* days */ + item_num = 2; + value_num /= 1440; + } else if (value_num && !(value_num % 60)) { + /* hours */ + item_num = 1; + value_num /= 60; + } + + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), item_num); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), value_num); + + if (lbl) + gtk_label_set_mnemonic_widget (GTK_LABEL (lbl), spin); + + g_object_set_data_full (G_OBJECT (spin), EPU_SP_NAME, g_strdup (source_property), g_free); + + g_object_set_data (G_OBJECT (combo), "refresh-spin", spin); + g_object_set_data (G_OBJECT (spin), "refresh-combo", combo); + g_object_set_data (G_OBJECT (hbox), "refresh-spin", spin); + g_object_set_data (G_OBJECT (hbox), "refresh-combo", combo); + g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (epu_refresh_combo_changed_cb), source); + g_signal_connect (G_OBJECT (spin), "value-changed", G_CALLBACK (epu_refresh_spin_changed_cb), source); + + if (parent) + gtk_table_attach (GTK_TABLE (parent), hbox, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); + + return hbox; +} diff --git a/e-util/e-plugin-util.h b/e-util/e-plugin-util.h new file mode 100644 index 0000000000..6bee4d0413 --- /dev/null +++ b/e-util/e-plugin-util.h @@ -0,0 +1,46 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * + * Copyright (C) 1999-2010 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _E_PLUGIN_UTIL_H +#define _E_PLUGIN_UTIL_H + +#include <glib.h> +#include <gtk/gtk.h> + +#include <libsoup/soup.h> + +#include <libedataserver/e-source.h> +#include <libedataserver/e-source.h> + +gboolean e_plugin_util_is_source_proto (ESource *source, const gchar *protocol); +gboolean e_plugin_util_is_group_proto (ESourceGroup *group, const gchar *protocol); + +gchar *e_plugin_util_replace_at_sign (const gchar *str); +gchar *e_plugin_util_uri_no_proto (SoupURI *uri); + +/* common widgets used in plugin setup */ +GtkWidget *e_plugin_util_add_entry (GtkWidget *parent, const gchar *label, ESource *source, const gchar *source_property); +GtkWidget *e_plugin_util_add_check (GtkWidget *parent, const gchar *label, ESource *source, const gchar *source_property, const gchar *true_value, const gchar *false_value); + +/* multipack widgets */ +GtkWidget *e_plugin_util_add_refresh (GtkWidget *parent, const gchar *label, ESource *source, const gchar *source_property); + +#endif /* _E_PLUGIN_UTIL_H */ |