diff options
-rw-r--r-- | calendar/ChangeLog | 63 | ||||
-rw-r--r-- | calendar/gui/Makefile.am | 2 | ||||
-rw-r--r-- | calendar/gui/apps_evolution_calendar.schemas.in.in | 12 | ||||
-rw-r--r-- | calendar/gui/calendar-commands.c | 32 | ||||
-rw-r--r-- | calendar/gui/calendar-component.c | 43 | ||||
-rw-r--r-- | calendar/gui/calendar-config-keys.h | 3 | ||||
-rw-r--r-- | calendar/gui/calendar-config.c | 13 | ||||
-rw-r--r-- | calendar/gui/calendar-config.h | 3 | ||||
-rw-r--r-- | calendar/gui/dialogs/Makefile.am | 8 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.c | 472 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.glade | 269 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.h | 59 | ||||
-rw-r--r-- | calendar/gui/dialogs/url-editor-dialog.c | 360 | ||||
-rw-r--r-- | calendar/gui/dialogs/url-editor-dialog.glade | 501 | ||||
-rw-r--r-- | calendar/gui/dialogs/url-editor-dialog.h | 68 | ||||
-rw-r--r-- | calendar/gui/e-cal-view.c | 30 | ||||
-rw-r--r-- | calendar/gui/e-calendar-view.c | 30 | ||||
-rw-r--r-- | calendar/gui/e-pub-utils.c | 310 | ||||
-rw-r--r-- | calendar/gui/e-pub-utils.h | 62 | ||||
-rw-r--r-- | calendar/gui/itip-utils.c | 221 | ||||
-rw-r--r-- | calendar/gui/itip-utils.h | 5 |
21 files changed, 2439 insertions, 127 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 3cb1db4edd..ad5a7da3a7 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,66 @@ + 2004-01-12 Gary Ekker <gekker@novell.com> + + * gui/Makefile.am: add e-pub-utils.[ch] + for Free/Busy publishing + + * gui/apps_evolution_calendar.schemas.in.in: add schema for + /apps/evo/calendar/free_busy key + + * gui/calendar-commands.c (publish_freebusy_cmd): change to + publish component rather than attach as email + + * gui/calendar-config-keys.h: add free_busy/urls key definition + + * gui/calendar-config.[ch] (calendar_config_get_free_busy): new + method for retrieving FB gconf key + (calendar_config_set_free_busy): new method for saving FB + gconf key + + * gui/e-cal-view.c (on_publish): change to publish component + rather than attach as email + + * gui/itip-utils.[ch] (itip_publish_begin): new method to process + e_cal_components and aggregate the data if we are publishing + for multiple calendars + (itip_publish_comp): new method to publish the ical data to an + http server via libsoup + (comp_fb_normalize): new static method to ensure rfc 2446 compliant + data before publishing icalcomponent_get_uid + (fb_sort): new static method to sort FB properties in ascending order + + * gui/dialogs/Makefile.am: add url-editor-dialog.[ch] and + url-editor-dialog.glade for configure FB publishing + + * gui/dialogs/cal-prefs-dialog.[ch] (cal_prefs_dialog_url_add_clicked): + (cal_prefs_dialog_url_edit_clicked):new method for events in FB tab + of cal-prefs-dialog + (cal_prefs_dialog_url_remove_clicked): ditto + (cal_prefs_dialog_url_enable_clicked): ditto + (cal_prefs_dialog_url_url_list_change): ditto + (cal_prefs_dialog_url_url_list_enable_toggled): ditto + (cal_prefs_dialog_url_url_list_double_click): ditto + (show_fb_config): new method for updating dialog with FB specific + data in gconf + (update_fb_config): new method for updating gconf with FB specific + data from dialogs + (setup_changes): detect changes in url_list gtk_tree_view + (get_widgets): include new dialog widgets for FB config + (init_widgets): connect signals for new FB config widgets + + * gui/dialogs/cal-prefs-dialog.glade: add new widgets for FB config + + * gui/dialogs/url-editor-dialog.[ch]: add files for FB url-editor dialog + + * gui/dialogs/url-editor-dialog.glade: ditto + + * gui/e-pub-utils.[ch]: add files with FB publishing utilities + + * gui/calendar-component.c (init_calendar_publishing): sets up + listeners to publish calendar, g_idle_add, and on gconf change + (init_calendar_publishing_cb): ditto + (conf_changed_callback): ditto + (impl_createControls): ditto + 2004-01-12 Rodrigo Moya <rodrigo@ximian.com> * gui/calendar-component.c (impl_upgradeFromVersion): sync the source diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index a6e4ab0f66..fe5916c50b 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -166,6 +166,8 @@ libevolution_calendar_la_SOURCES = \ e-meeting-utils.h \ e-mini-calendar-config.c \ e-mini-calendar-config.h \ + e-pub-utils.c \ + e-pub-utils.h \ e-select-names-editable.c \ e-select-names-editable.h \ e-select-names-renderer.c \ diff --git a/calendar/gui/apps_evolution_calendar.schemas.in.in b/calendar/gui/apps_evolution_calendar.schemas.in.in index 27e9aa44e2..b42d3f8498 100644 --- a/calendar/gui/apps_evolution_calendar.schemas.in.in +++ b/calendar/gui/apps_evolution_calendar.schemas.in.in @@ -355,5 +355,17 @@ <short>Programs that can run as part of alarms</short> </locale> </schema> + + <schema> + <key>/schemas/apps/evolution/calendar/publish/uris</key> + <applyto>/apps/evolution/calendar/publish/uris</applyto> + <owner>evolution-calendar</owner> + <type>list</type> + <list_type>string</list_type> + <default>[]</default> + <locale name="C"> + <short>List of urls for free/busy publishing</short> + </locale> + </schema> </schemalist> </gconfschemafile> diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c index 6defec9819..1ff2a3a0a8 100644 --- a/calendar/gui/calendar-commands.c +++ b/calendar/gui/calendar-commands.c @@ -60,6 +60,7 @@ #include "print.h" #include "dialogs/cal-prefs-dialog.h" #include "itip-utils.h" +#include "e-pub-utils.h" #include "evolution-shell-component-utils.h" /* Focusing information for the calendar view. We have to keep track of this @@ -319,36 +320,7 @@ delete_occurrence_cmd (BonoboUIComponent *uic, gpointer data, const gchar *path) static void publish_freebusy_cmd (BonoboUIComponent *uic, gpointer data, const gchar *path) { - GnomeCalendar *gcal; - GList *client_list, *cl; - GList *comp_list = NULL; - icaltimezone *utc; - time_t start = time (NULL), end; - - gcal = GNOME_CALENDAR (data); - - utc = icaltimezone_get_utc_timezone (); - start = time_day_begin_with_zone (start, utc); - end = time_add_week_with_zone (start, 6, utc); - - /* FIXME Should we aggregate the data? */ - client_list = e_cal_model_get_client_list (gnome_calendar_get_calendar_model (gcal)); - for (cl = client_list; cl != NULL; cl = cl->next) { - if (e_cal_get_free_busy ((ECal *) cl->data, NULL, start, end, &comp_list, NULL)) { - GList *l; - - for (l = comp_list; l; l = l->next) { - ECalComponent *comp = E_CAL_COMPONENT (l->data); - itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, (ECal *) cl->data, NULL); - - g_object_unref (comp); - } - - g_list_free (comp_list); - } - } - - g_list_free (client_list); + e_pub_publish (TRUE); } static void diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c index 03725c560c..ddcff4165c 100644 --- a/calendar/gui/calendar-component.c +++ b/calendar/gui/calendar-component.c @@ -30,6 +30,8 @@ #include <bonobo/bonobo-control.h> #include <bonobo/bonobo-i18n.h> #include <bonobo/bonobo-exception.h> +#include "e-pub-utils.h" +#include "calendar-config-keys.h" #include "calendar-config.h" #include "calendar-component.h" #include "calendar-commands.h" @@ -59,6 +61,7 @@ struct _CalendarComponentPrivate { char *config_directory; GConfClient *gconf_client; + int gconf_notify_id; ESourceList *source_list; GSList *source_selection; @@ -435,6 +438,25 @@ config_primary_selection_changed_cb (GConfClient *client, guint id, GConfEntry * update_primary_selection (data); } +static gboolean +init_calendar_publishing_cb (gpointer data) +{ + /* Publish if it is time to publish again */ + e_pub_publish (FALSE); + + return FALSE; +} + +static void +conf_changed_callback (GConfClient *client, + unsigned int connection_id, + GConfEntry *entry, + void *user_data) +{ + /* publish config changed, so publish */ + e_pub_publish (TRUE); +} + /* GObject methods. */ static void @@ -582,6 +604,24 @@ impl_upgradeFromVersion (PortableServer_Servant servant, } static void +init_calendar_publishing (CalendarComponent *calendar_component) +{ + guint idle_id = 0; + CalendarComponentPrivate *priv; + + priv = calendar_component->priv; + + gconf_client_add_dir (priv->gconf_client, CALENDAR_CONFIG_PUBLISH, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + priv->gconf_notify_id + = gconf_client_notify_add (priv->gconf_client, CALENDAR_CONFIG_PUBLISH, + (GConfClientNotifyFunc) conf_changed_callback, NULL, + NULL, NULL); + + idle_id = g_idle_add ((GSourceFunc) init_calendar_publishing_cb, GINT_TO_POINTER (idle_id)); +} + +static void impl_createControls (PortableServer_Servant servant, Bonobo_Control *corba_sidebar_control, Bonobo_Control *corba_view_control, @@ -629,6 +669,9 @@ impl_createControls (PortableServer_Servant servant, gtk_widget_show (statusbar_widget); statusbar_control = bonobo_control_new (statusbar_widget); + /* Initialize Calendar Publishing */ + init_calendar_publishing (calendar_component); + /* connect after setting the initial selections, or we'll get unwanted calls to calendar_control_sensitize_calendar_commands */ g_signal_connect_object (priv->source_selector, "selection_changed", diff --git a/calendar/gui/calendar-config-keys.h b/calendar/gui/calendar-config-keys.h index ebe16b6539..bdcad1476e 100644 --- a/calendar/gui/calendar-config-keys.h +++ b/calendar/gui/calendar-config-keys.h @@ -70,6 +70,9 @@ G_BEGIN_DECLS #define CALENDAR_CONFIG_DEFAULT_REMINDER_INTERVAL CALENDAR_CONFIG_PREFIX "/other/default_reminder_interval" #define CALENDAR_CONFIG_DEFAULT_REMINDER_UNITS CALENDAR_CONFIG_PREFIX "/other/default_reminder_units" +/* Free/Busy settings */ +#define CALENDAR_CONFIG_PUBLISH CALENDAR_CONFIG_PREFIX"/publish/uris" + G_END_DECLS #endif diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c index fea9311b2c..55317a4bd3 100644 --- a/calendar/gui/calendar-config.c +++ b/calendar/gui/calendar-config.c @@ -1025,3 +1025,16 @@ calendar_config_get_hide_completed_tasks_sexp (void) return sexp; } +GSList * +calendar_config_get_free_busy (void) +{ + return gconf_client_get_list (config, CALENDAR_CONFIG_PUBLISH, + GCONF_VALUE_STRING, NULL); +} + +void +calendar_config_set_free_busy (GSList *url_list) +{ + gconf_client_set_list (config, CALENDAR_CONFIG_PUBLISH, + GCONF_VALUE_STRING, url_list, NULL); +} diff --git a/calendar/gui/calendar-config.h b/calendar/gui/calendar-config.h index ff34febd91..ac9affce00 100644 --- a/calendar/gui/calendar-config.h +++ b/calendar/gui/calendar-config.h @@ -202,6 +202,9 @@ void calendar_config_set_default_reminder_interval (int interval); CalUnits calendar_config_get_default_reminder_units (void); void calendar_config_set_default_reminder_units (CalUnits units); +/* Free/Busy Settings */ +GSList * calendar_config_get_free_busy (void); +void calendar_config_set_free_busy (GSList * url_list); /* Convenience functions to configure common properties of ECalendar, EDateEdit & ECalendarTable widgets, and the ECellDateEdit ETable cell. */ diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am index 18a83fb4de..bd6876f63b 100644 --- a/calendar/gui/dialogs/Makefile.am +++ b/calendar/gui/dialogs/Makefile.am @@ -78,7 +78,9 @@ libcal_dialogs_la_SOURCES = \ task-details-page.c \ task-details-page.h \ task-page.c \ - task-page.h + task-page.h \ + url-editor-dialog.c \ + url-editor-dialog.h glade_DATA = \ alarm-options.glade \ @@ -91,8 +93,8 @@ glade_DATA = \ recurrence-page.glade \ schedule-page.glade \ task-details-page.glade \ - task-page.glade - + task-page.glade \ + url-editor-dialog.glade CLEANFILES = $(BUILT_SOURCES) diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c index 83363a3ac0..635c665cc1 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.c +++ b/calendar/gui/dialogs/cal-prefs-dialog.c @@ -34,10 +34,16 @@ #include "../e-timezone-entry.h" #include "cal-prefs-dialog.h" #include "../calendar-config.h" +#include "url-editor-dialog.h" +#include <gtk/gtk.h> +#include <gtk/gtkmain.h> #include <gtk/gtksignal.h> #include <gtk/gtkoptionmenu.h> #include <gtk/gtktogglebutton.h> +#include <libxml/tree.h> +#include <string.h> +#include <libgnome/gnome-i18n.h> #include <libgnomeui/gnome-color-picker.h> #include <glade/glade.h> #include <gal/util/e-util.h> @@ -45,40 +51,6 @@ #include <widgets/misc/e-dateedit.h> -struct _DialogData { - /* Glade XML data */ - GladeXML *xml; - - GtkWidget *page; - - GtkWidget *timezone; - GtkWidget *working_days[7]; - GtkWidget *week_start_day; - GtkWidget *start_of_day; - GtkWidget *end_of_day; - GtkWidget *use_12_hour; - GtkWidget *use_24_hour; - GtkWidget *time_divisions; - GtkWidget *show_end_times; - GtkWidget *compress_weekend; - GtkWidget *dnav_show_week_no; - - /* Widgets for the task list options */ - GtkWidget *tasks_due_today_color; - GtkWidget *tasks_overdue_color; - - GtkWidget *tasks_hide_completed_checkbutton; - GtkWidget *tasks_hide_completed_spinbutton; - GtkWidget *tasks_hide_completed_optionmenu; - - /* Other page options */ - GtkWidget *confirm_delete; - GtkWidget *default_reminder; - GtkWidget *default_reminder_interval; - GtkWidget *default_reminder_units; -}; -typedef struct _DialogData DialogData; - static const int week_start_day_map[] = { 1, 2, 3, 4, 5, 6, 0, -1 }; @@ -96,7 +68,6 @@ static const int default_reminder_units_map[] = { CAL_MINUTES, CAL_HOURS, CAL_DAYS, -1 }; - static gboolean get_widgets (DialogData *data); static void widget_changed_callback (GtkWidget *, void *data); @@ -115,8 +86,23 @@ static void cal_prefs_dialog_end_of_day_changed (GtkWidget *button, void *data); static void cal_prefs_dialog_start_of_day_changed (GtkWidget *button, void *data); static void cal_prefs_dialog_hide_completed_tasks_toggled (GtkWidget *button, void *data); +static void cal_prefs_dialog_url_add_clicked (GtkWidget *button, void *data); +static void cal_prefs_dialog_url_edit_clicked (GtkWidget *button, void *data); +static void cal_prefs_dialog_url_remove_clicked (GtkWidget *button, void *data); +static void cal_prefs_dialog_url_enable_clicked (GtkWidget *button, void *data); +static void cal_prefs_dialog_url_list_change (GtkTreeSelection *selection, + DialogData *dialog_data); +static void cal_prefs_dialog_url_list_enable_toggled (GtkCellRendererToggle *renderer, const char *path_string, void *data); +static void cal_prefs_dialog_url_list_double_click(GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + DialogData *dialog_data); +static void show_fb_config (DialogData *dialog_data); +static void update_fb_config (DialogData *dialog_data); + GtkWidget *cal_prefs_dialog_create_time_edit (void); +#define PREFS_WINDOW(dialog_data) GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (dialog_data), GTK_TYPE_WINDOW)) /** * cal_prefs_dialog_new: @@ -233,6 +219,8 @@ setup_changes (DialogData *dialog_data, connect_changed (dialog_data->default_reminder_interval, "changed", config_control); connect_changed (GTK_OPTION_MENU (dialog_data->default_reminder_units)->menu, "selection_done", config_control); + connect_changed ((GtkWidget *) gtk_tree_view_get_selection (dialog_data->url_list), "changed", config_control); + /* These use GnomeColorPicker so we have to use a different signal. */ g_signal_connect((dialog_data->tasks_due_today_color), "color_set", G_CALLBACK (color_set_callback), config_control); @@ -282,6 +270,12 @@ get_widgets (DialogData *data) data->default_reminder = GW ("default-reminder"); data->default_reminder_interval = GW ("default-reminder-interval"); data->default_reminder_units = GW ("default-reminder-units"); + + data->url_add = GW ("url_add"); + data->url_edit = GW ("url_edit"); + data->url_remove = GW ("url_remove"); + data->url_enable = GW ("url_enable"); + data->url_list = GTK_TREE_VIEW (GW ("url_list")); #undef GW @@ -311,7 +305,12 @@ get_widgets (DialogData *data) && data->confirm_delete && data->default_reminder && data->default_reminder_interval - && data->default_reminder_units); + && data->default_reminder_units + && data->url_add + && data->url_edit + && data->url_remove + && data->url_enable + && data->url_list); } @@ -361,6 +360,13 @@ cal_prefs_dialog_create_time_edit (void) static void init_widgets (DialogData *dialog_data) { + GtkCellRenderer *renderer = NULL; + GtkTreeSelection *selection; + GtkListStore *model; + + dialog_data->url_editor = FALSE; + dialog_data->url_editor_dlg =NULL; + g_signal_connect((dialog_data->use_24_hour), "toggled", G_CALLBACK (cal_prefs_dialog_use_24_hour_toggled), dialog_data); @@ -377,8 +383,65 @@ init_widgets (DialogData *dialog_data) "toggled", G_CALLBACK (cal_prefs_dialog_hide_completed_tasks_toggled), dialog_data); -} + + /* Free/Busy ... */ + g_signal_connect ((dialog_data->url_add), "clicked", + G_CALLBACK (cal_prefs_dialog_url_add_clicked), + dialog_data); + + g_signal_connect ((dialog_data->url_edit), "clicked", + G_CALLBACK (cal_prefs_dialog_url_edit_clicked), + dialog_data); + g_signal_connect ((dialog_data->url_remove), "clicked", + G_CALLBACK (cal_prefs_dialog_url_remove_clicked), + dialog_data); + + g_signal_connect ((dialog_data->url_enable), "clicked", + G_CALLBACK (cal_prefs_dialog_url_enable_clicked), + dialog_data); + + /* Free/Busy Listview */ + renderer = gtk_cell_renderer_toggle_new(); + g_object_set ((GObject *) renderer, "activatable", TRUE, NULL); + + model = gtk_list_store_new (URL_LIST_N_COLUMNS, G_TYPE_BOOLEAN, + G_TYPE_STRING, G_TYPE_POINTER); + + gtk_tree_view_set_model (dialog_data->url_list, + (GtkTreeModel *) model); + + gtk_tree_view_insert_column_with_attributes (dialog_data->url_list, -1, + _("Enabled"), renderer, + "active", + URL_LIST_ENABLED_COLUMN, + NULL); + + g_signal_connect (renderer, "toggled", + G_CALLBACK (cal_prefs_dialog_url_list_enable_toggled), + dialog_data); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_insert_column_with_attributes (dialog_data->url_list, -1, + _("Location"), renderer, + "text", + URL_LIST_LOCATION_COLUMN, + NULL); + + selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + gtk_tree_view_set_headers_visible ((GtkTreeView *) dialog_data->url_list, TRUE); + + + g_signal_connect (gtk_tree_view_get_selection (dialog_data->url_list), + "changed", + G_CALLBACK (cal_prefs_dialog_url_list_change), + dialog_data); + + g_signal_connect (dialog_data->url_list, "row-activated", + G_CALLBACK (cal_prefs_dialog_url_list_double_click), + dialog_data); +} static void cal_prefs_dialog_use_24_hour_toggled (GtkWidget *button, @@ -479,6 +542,300 @@ set_color_picker (GtkWidget *picker, const char *spec) 65535); } +static void +cal_prefs_dialog_url_add_clicked (GtkWidget *button, void *data) +{ + DialogData *dialog_data = (DialogData *) data; + EPublishUri *url = NULL; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeSelection *selection; + + model = gtk_tree_view_get_model (dialog_data->url_list); + url = g_new0 (EPublishUri, 1); + url->enabled = TRUE; + url->location = ""; + + if (!dialog_data->url_editor) { + + dialog_data->url_editor = url_editor_dialog_new (dialog_data, + url); + + if (url->location != "") { + gtk_list_store_append(GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, + URL_LIST_ENABLED_COLUMN, + url->enabled, + URL_LIST_LOCATION_COLUMN, + g_strdup (url->location), + URL_LIST_FREE_BUSY_URL_COLUMN, url, + -1); + + if (!GTK_WIDGET_SENSITIVE ((GtkWidget *) dialog_data->url_remove)) { + selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list); + gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter); + gtk_widget_set_sensitive ((GtkWidget*) dialog_data->url_remove, TRUE); + gtk_tree_selection_select_iter (selection, &iter); + } + } + dialog_data->url_editor = FALSE; + dialog_data->url_editor_dlg = NULL; + } else { + gdk_window_raise (dialog_data->url_editor_dlg->window); + } +} + +static void +cal_prefs_dialog_url_edit_clicked (GtkWidget *button, void *data) +{ + DialogData *dialog_data = (DialogData *) data; + + if (!dialog_data->url_editor) { + GtkTreeSelection *selection; + EPublishUri *url = NULL; + GtkTreeModel *model; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list); + if (gtk_tree_selection_get_selected (selection, &model, &iter)){ + gtk_tree_model_get (model, &iter, + URL_LIST_FREE_BUSY_URL_COLUMN, + &url, + -1); + + } + + if (url) { + + dialog_data->url_editor = url_editor_dialog_new (dialog_data, url); + + gtk_list_store_set ((GtkListStore *) model, &iter, + URL_LIST_LOCATION_COLUMN, + g_strdup (url->location), + URL_LIST_ENABLED_COLUMN, + url->enabled, + URL_LIST_FREE_BUSY_URL_COLUMN, url, + -1); + + if (!GTK_WIDGET_SENSITIVE ((GtkWidget *) dialog_data->url_remove)) { + selection = gtk_tree_view_get_selection ((GtkTreeView *) dialog_data->url_list); + gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter); + gtk_widget_set_sensitive ((GtkWidget*) dialog_data->url_remove, TRUE); + gtk_tree_selection_select_iter (selection, &iter); + } + dialog_data->url_editor = FALSE; + dialog_data->url_editor_dlg = NULL; + } + } else { + gdk_window_raise (dialog_data->url_editor_dlg->window); + } +} + +static void +cal_prefs_dialog_url_remove_clicked (GtkWidget *button, void *data) +{ + DialogData *dialog_data = (DialogData *) data; + EPublishUri *url = NULL; + GtkTreeSelection * selection; + GtkTreeModel *model; + GtkWidget *confirm; + GtkTreeIter iter; + int ans; + + selection = gtk_tree_view_get_selection (dialog_data->url_list); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + gtk_tree_model_get (model, &iter, + URL_LIST_FREE_BUSY_URL_COLUMN, &url, + -1); + + /* make sure we have a valid account selected and that + we aren't editing anything... */ + if (url == NULL || dialog_data->url_editor) + return; + + confirm = gtk_message_dialog_new (PREFS_WINDOW (dialog_data), + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Are you sure you want to remove this URL?")); + + (GtkButton *) button = gtk_button_new_from_stock (GTK_STOCK_YES); + gtk_button_set_label ((GtkButton *) button, _("Remove")); + gtk_dialog_add_action_widget ((GtkDialog *) confirm, (GtkWidget *) button, GTK_RESPONSE_YES); + gtk_widget_show ((GtkWidget *) button); + + (GtkButton *) button = gtk_button_new_from_stock (GTK_STOCK_NO); + gtk_button_set_label ((GtkButton *) button, _("Don't Remove")); + gtk_dialog_add_action_widget ((GtkDialog *) confirm, + (GtkWidget *) button, GTK_RESPONSE_NO); + + gtk_widget_show ((GtkWidget *) button); + + ans = gtk_dialog_run ((GtkDialog *) confirm); + gtk_widget_destroy (confirm); + + if (ans == GTK_RESPONSE_YES) { + int len; + + gtk_list_store_remove ((GtkListStore *) model, &iter); + + len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL); + if (len > 0) { + gtk_tree_selection_select_iter (selection, &iter); + } else { + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_edit), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_remove), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_enable), FALSE); + } + g_free (url); + } +} + +static void +cal_prefs_dialog_url_enable_clicked (GtkWidget *button, void *data) +{ + DialogData *dialog_data = (DialogData *) data; + EPublishUri *url = NULL; + GtkTreeSelection * selection; + GtkTreeModel *model; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection (dialog_data->url_list); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, + URL_LIST_FREE_BUSY_URL_COLUMN, &url, + -1); + url->enabled = !url->enabled; + gtk_list_store_set ((GtkListStore *) model, &iter, + URL_LIST_ENABLED_COLUMN, url->enabled, + -1); + + gtk_button_set_label ((GtkButton *) dialog_data->url_enable, + url->enabled ? _("Disable") : _("Enable")); + } +} + +static void +cal_prefs_dialog_url_list_enable_toggled (GtkCellRendererToggle *renderer, + const char *path_string, + void *data) +{ + DialogData *dialog_data = (DialogData *) data; + GtkTreeSelection * selection; + EPublishUri *url = NULL; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_path_new_from_string (path_string); + model = gtk_tree_view_get_model (dialog_data->url_list); + selection = gtk_tree_view_get_selection (dialog_data->url_list); + + if (gtk_tree_model_get_iter (model, &iter, path)) { + gtk_tree_model_get (model, &iter, + URL_LIST_FREE_BUSY_URL_COLUMN, &url, + -1); + + url->enabled = !url->enabled; + gtk_list_store_set((GtkListStore *) model, &iter, + URL_LIST_ENABLED_COLUMN, + url->enabled, -1); + + if (gtk_tree_selection_iter_is_selected (selection, &iter)) + gtk_button_set_label ((GtkButton *) dialog_data->url_enable, + url->enabled ? _("Disable") : _("Enable")); + } + + gtk_tree_path_free (path); +} + +static void +cal_prefs_dialog_url_list_double_click (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + DialogData *dialog_data) +{ + cal_prefs_dialog_url_edit_clicked (NULL, dialog_data); +} + +static void +cal_prefs_dialog_url_list_change (GtkTreeSelection *selection, + DialogData *dialog_data) +{ + EPublishUri *url = NULL; + GtkTreeModel *model; + GtkTreeIter iter; + int state; + + state = gtk_tree_selection_get_selected (selection, &model, &iter); + if (state) { + gtk_tree_model_get (model, &iter, + URL_LIST_FREE_BUSY_URL_COLUMN, &url, + -1); + + if (url->location && url->enabled) + gtk_button_set_label ((GtkButton *) dialog_data->url_enable, _("Disable")); + else + gtk_button_set_label ((GtkButton *) dialog_data->url_enable, _("Enable")); + } else { + gtk_widget_grab_focus (GTK_WIDGET (dialog_data->url_add)); + } + + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_edit), state); + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_remove), state); + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_enable), state); +} + +/* Shows the current Free/Busy settings in the dialog */ +static void +show_fb_config (DialogData *dialog_data) +{ + GSList *url_config_list; + GtkListStore *model; + GtkTreeIter iter; + + model = (GtkListStore *) gtk_tree_view_get_model (dialog_data->url_list); + gtk_list_store_clear (model); + + /* restore urls from gconf */ + url_config_list = calendar_config_get_free_busy(); + + while (url_config_list) { + gchar *xml = (gchar *)url_config_list->data; + EPublishUri *url; + url = g_new0 (EPublishUri, 1); + + e_pub_uri_from_xml (url, xml); + if (url->location) { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + URL_LIST_ENABLED_COLUMN, + url->enabled, + URL_LIST_LOCATION_COLUMN, + url->location, + URL_LIST_FREE_BUSY_URL_COLUMN, url, + -1); + } + + url_config_list = g_slist_next (url_config_list); + g_free (xml); + } + + g_slist_foreach (url_config_list, (GFunc) g_free, NULL); + g_slist_free (url_config_list); + if (!gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter)) { + /* list is empty-disable edit, remove, and enable buttons */ + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_edit), + FALSE); + + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_remove), + FALSE); + + gtk_widget_set_sensitive (GTK_WIDGET (dialog_data->url_enable), + FALSE); + } +} + /* Shows the current task list settings in the dialog */ static void show_task_list_config (DialogData *dialog_data) @@ -576,6 +933,9 @@ show_config (DialogData *dialog_data) /* Task list */ show_task_list_config (dialog_data); + + /* Free/Busy */ + show_fb_config (dialog_data); /* Other page */ @@ -605,6 +965,41 @@ spec_from_picker (GtkWidget *picker) return spec; } +/* Updates the Free/Busy config values from the settings in the dialog*/ +static void +update_fb_config (DialogData *dialog_data) +{ + GtkTreeIter iter; + GtkListStore *model = NULL; + gboolean valid; + GSList *url_list; + + url_list = NULL; + + model = (GtkListStore *) gtk_tree_view_get_model (dialog_data->url_list); + + valid = gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter); + while (valid) { + EPublishUri *url; + gchar *xml; + + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + URL_LIST_FREE_BUSY_URL_COLUMN, &url, + -1); + + xml = e_pub_uri_to_xml (url); + if (xml != NULL) { + url_list = g_slist_append(url_list, xml); + } + g_free (url); + + valid = gtk_tree_model_iter_next((GtkTreeModel *) model, &iter); + } + calendar_config_set_free_busy (url_list); + + g_slist_free (url_list); +} + /* Updates the task list config values from the settings in the dialog */ static void update_task_list_config (DialogData *dialog_data) @@ -671,6 +1066,9 @@ update_config (DialogData *dialog_data) /* Task list */ update_task_list_config (dialog_data); + + /* Free/Busy */ + update_fb_config (dialog_data); /* Other page */ diff --git a/calendar/gui/dialogs/cal-prefs-dialog.glade b/calendar/gui/dialogs/cal-prefs-dialog.glade index d566368611..5f74153dda 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.glade +++ b/calendar/gui/dialogs/cal-prefs-dialog.glade @@ -891,7 +891,6 @@ <child> <widget class="GtkVBox" id="vbox8"> - <property name="border_width">6</property> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">6</property> @@ -1305,6 +1304,274 @@ <property name="type">tab</property> </packing> </child> + + <child> + <widget class="GtkHBox" id="hbox20"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="url_list"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox15"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label44"> + <property name="height_request">34</property> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">3</property> + + <child> + <widget class="GtkButton" id="url_add"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + + <child> + <widget class="GtkAlignment" id="alignment5"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkHBox" id="hbox22"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-add</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="labeladd"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Add URL</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="url_edit"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Edit</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="url_remove"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label45"> + <property name="height_request">34</property> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox4"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">3</property> + + <child> + <widget class="GtkButton" id="url_enable"> + <property name="width_request">91</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">E_nable</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label46"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label42"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Free/Busy Publishing</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> diff --git a/calendar/gui/dialogs/cal-prefs-dialog.h b/calendar/gui/dialogs/cal-prefs-dialog.h index db6f5a75fa..8905cb618b 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.h +++ b/calendar/gui/dialogs/cal-prefs-dialog.h @@ -30,10 +30,69 @@ #ifndef _CAL_PREFS_DIALOG_H_ #define _CAL_PREFS_DIALOG_H_ +#include <gtk/gtk.h> +#include <glade/glade.h> +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> +#include "../e-pub-utils.h" #include "evolution-config-control.h" G_BEGIN_DECLS +enum { + URL_LIST_ENABLED_COLUMN, + URL_LIST_LOCATION_COLUMN, + URL_LIST_FREE_BUSY_URL_COLUMN, + URL_LIST_N_COLUMNS +}; + +struct _DialogData { + /* Glade XML data */ + GladeXML *xml; + + GConfClient *gconf; + + GtkWidget *page; + + GtkWidget *timezone; + GtkWidget *working_days[7]; + GtkWidget *week_start_day; + GtkWidget *start_of_day; + GtkWidget *end_of_day; + GtkWidget *use_12_hour; + GtkWidget *use_24_hour; + GtkWidget *time_divisions; + GtkWidget *show_end_times; + GtkWidget *compress_weekend; + GtkWidget *dnav_show_week_no; + + /* Widgets for the task list options */ + GtkWidget *tasks_due_today_color; + GtkWidget *tasks_overdue_color; + + GtkWidget *tasks_hide_completed_checkbutton; + GtkWidget *tasks_hide_completed_spinbutton; + GtkWidget *tasks_hide_completed_optionmenu; + + /* Widgets for the Free/Busy options */ + GtkWidget *url_add; + GtkWidget *url_edit; + GtkWidget *url_remove; + GtkWidget *url_enable; + GtkTreeView *url_list; + gboolean url_editor; + GtkWidget* url_editor_dlg; + guint destroyed : 1; + + + /* Other page options */ + GtkWidget *confirm_delete; + GtkWidget *default_reminder; + GtkWidget *default_reminder_interval; + GtkWidget *default_reminder_units; +}; +typedef struct _DialogData DialogData; + EvolutionConfigControl *cal_prefs_dialog_new (void); G_END_DECLS diff --git a/calendar/gui/dialogs/url-editor-dialog.c b/calendar/gui/dialogs/url-editor-dialog.c new file mode 100644 index 0000000000..ec1e493402 --- /dev/null +++ b/calendar/gui/dialogs/url-editor-dialog.c @@ -0,0 +1,360 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Gary Ekker <gekker@novell.com> + * + * Copyright 2004 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* + * UrlEditorDialog - a GtkObject which handles a libglade-loaded dialog + * to edit the calendar preference settings. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include "cal-prefs-dialog.h" +#include "url-editor-dialog.h" + +#include <gtk/gtk.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtktogglebutton.h> +#include <libgnomeui/gnome-color-picker.h> +#include <glade/glade.h> +#include <gal/util/e-util.h> +#include <e-util/e-dialog-widgets.h> +#include <widgets/misc/e-dateedit.h> +#include <stdlib.h> +#include <string.h> + +static gboolean get_widgets (UrlDialogData *data); +static void init_widgets (UrlDialogData *data); + +static void url_editor_dialog_fb_url_changed (GtkEntry *url_entry, void *data); +static void url_editor_dialog_fb_daily_toggled (GtkWidget *button, void *data); +static void url_editor_dialog_fb_url_activated (GtkEntry *url_entry, void *data); +static void url_editor_dialog_fb_ok_enable (GtkWidget *widget, void *data); + +/** + * url_editor_dialog_new: + * + * Creates a new #UrlEditorDialog. + * + * Return value: a new #UrlEditorDialog. + **/ +gboolean +url_editor_dialog_new (DialogData *dialog_data, EPublishUri *uri) +{ + int b; + + UrlDialogData *url_dlg_data = g_new0 (UrlDialogData, 1); + url_dlg_data->xml = glade_xml_new (EVOLUTION_GLADEDIR "/url-editor-dialog.glade", NULL, NULL); + if (!url_dlg_data->xml) { + g_message ("url_editor_dialog_construct(): Could not load the Glade XML file!"); + return FALSE; + } + + if (!get_widgets (url_dlg_data)) { + g_message ("url_editor_dialog_construct(): Could not find all widgets in the XML file!"); + return FALSE; + } + + url_dlg_data->url_dialog = (GtkWidget *) dialog_data; + url_dlg_data->url_data = uri; + + init_widgets (url_dlg_data); + if (uri->location && uri->username && uri->password) { + if (strlen(uri->location) != 0) { + gtk_entry_set_text (url_dlg_data->url_entry, + uri->location); + } + if (strlen(uri->username) != 0) { + gtk_entry_set_text (url_dlg_data->username_entry, + uri->username); + } + if (strlen(uri->password) != 0) { + gtk_entry_set_text (url_dlg_data->password_entry, + uri->password); + + e_dialog_toggle_set (url_dlg_data->remember_pw, TRUE); + } else { + e_dialog_toggle_set (url_dlg_data->remember_pw, FALSE); + } + + switch (uri->publish_freq) { + case URI_PUBLISH_DAILY: + e_dialog_radio_set (url_dlg_data->daily, + URI_PUBLISH_DAILY, + pub_frequency_type_map); + break; + case URI_PUBLISH_WEEKLY: + e_dialog_radio_set (url_dlg_data->daily, + URI_PUBLISH_WEEKLY, + pub_frequency_type_map); + break; + case URI_PUBLISH_USER: + default: + e_dialog_radio_set (url_dlg_data->daily, + URI_PUBLISH_USER, + pub_frequency_type_map); + } + } + dialog_data->url_editor=TRUE; + dialog_data->url_editor_dlg = (GtkWidget *) url_dlg_data; + gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, FALSE); + + b = gtk_dialog_run ((GtkDialog *) url_dlg_data->url_editor); + + if (b == GTK_RESPONSE_OK) { + if ((GtkEntry *) url_dlg_data->url_entry) { + url_editor_dialog_fb_url_activated (url_dlg_data->url_entry, url_dlg_data); + url_dlg_data->url_data->username = g_strdup (gtk_entry_get_text ((GtkEntry *) url_dlg_data->username_entry)); + if (e_dialog_toggle_get (url_dlg_data->remember_pw)) + url_dlg_data->url_data->password = g_strdup (gtk_entry_get_text ((GtkEntry *) url_dlg_data->password_entry)); + } + } + + gtk_widget_destroy (url_dlg_data->url_editor); + g_object_unref (url_dlg_data->xml); + g_free (url_dlg_data); + url_dlg_data = NULL; + + return FALSE; +} + +static gboolean +get_widgets (UrlDialogData *data) +{ +#define GW(name) glade_xml_get_widget (data->xml, name) + + data->url_editor = GW ("url_editor"); + data->url_dialog = GW ("fb_dialog"); + data->url_entry = GTK_ENTRY (GW ("url_entry")); + data->daily = GW ("daily"); + data->weekly = GW ("weekly"); + data->user_publish = GW ("user_publish"); + data->scrolled_window = GW ("scrolled_window"); + data->username_entry = GTK_ENTRY (GW ("username_entry")); + data->password_entry = GTK_ENTRY (GW ("password_entry")); + data->remember_pw = GW ("remember_pw"); + data->cancel = GW ("cancel"); + data->ok = GW ("ok"); + +#undef GW + + return (data ->url_editor + && data->url_entry + && data->daily + && data->weekly + && data->user_publish + && data->scrolled_window + && data->username_entry + && data->password_entry + && data->remember_pw + && data->cancel + && data->ok); +} + +static void +selection_changed_callback (ESourceSelector *selector, + void *data) +{ + UrlDialogData *url_dlg_data = (UrlDialogData *) data; + GSList *selection = e_source_selector_get_selection (selector); + + if (selection != NULL) { + GSList *p, *l = NULL; + + for (p = selection; p != NULL; p = p->next) { + ESource *source = E_SOURCE(p->data); + gchar* source_uid = g_strdup(e_source_peek_uid(source)); + + l = g_slist_append (l, source_uid); + } + url_dlg_data->url_data->calendars = l; + } + + e_source_selector_free_selection (selection); + gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, TRUE); +} + +/* Connects any necessary signal handlers. */ +static void +init_widgets (UrlDialogData *url_dlg_data) +{ + GtkWidget *selector; + ESourceList *source_list; + GConfClient *gconf_client; + GSList *p; + + g_signal_connect (url_dlg_data->url_entry, "changed", + G_CALLBACK (url_editor_dialog_fb_url_changed), + url_dlg_data); + + g_signal_connect (url_dlg_data->username_entry, "changed", + G_CALLBACK (url_editor_dialog_fb_ok_enable), + url_dlg_data); + + g_signal_connect (url_dlg_data->password_entry, "changed", + G_CALLBACK (url_editor_dialog_fb_ok_enable), + url_dlg_data); + + g_signal_connect (url_dlg_data->remember_pw, "toggled", + G_CALLBACK (url_editor_dialog_fb_ok_enable), + url_dlg_data); + + g_signal_connect (url_dlg_data->url_entry, "activate", + G_CALLBACK (url_editor_dialog_fb_url_activated), + url_dlg_data); + + g_signal_connect (url_dlg_data->daily, "toggled", + G_CALLBACK (url_editor_dialog_fb_daily_toggled), + url_dlg_data); + + g_signal_connect (url_dlg_data->weekly, "toggled", + G_CALLBACK (url_editor_dialog_fb_daily_toggled), + url_dlg_data); + + g_signal_connect (url_dlg_data->user_publish, "toggled", + G_CALLBACK (url_editor_dialog_fb_daily_toggled), + url_dlg_data); + + + if (url_dlg_data->url_data->calendars) { + ESource *source; + + gconf_client = gconf_client_get_default (); + source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources"); + selector = e_source_selector_new (source_list); + + p = url_dlg_data->url_data->calendars; + for (; p != NULL; p = p->next) { + gchar *source_uid; + + source_uid = g_strdup (p->data); + source = e_source_list_peek_source_by_uid (source_list, source_uid); + e_source_selector_select_source ((ESourceSelector *)selector, source); + g_free (source_uid); + } + } else { + gconf_client = gconf_client_get_default (); + source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources"); + selector = e_source_selector_new (source_list); + } + e_source_selector_show_selection ((ESourceSelector *) selector, TRUE); + g_signal_connect (selector, "selection_changed", + G_CALLBACK (selection_changed_callback), + url_dlg_data); + + gtk_widget_show (selector); + gtk_container_add (GTK_CONTAINER (url_dlg_data->scrolled_window), + selector); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (url_dlg_data->scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (url_dlg_data->scrolled_window), + GTK_SHADOW_IN); + + gtk_widget_show (url_dlg_data->scrolled_window); +} + +static void +url_editor_dialog_fb_daily_toggled (GtkWidget *button, + void *data) +{ + UrlDialogData *url_dlg_data = (UrlDialogData *) data; + enum publish_frequency frequency; + + frequency = e_dialog_radio_get (url_dlg_data->daily, + pub_frequency_type_map); + url_dlg_data->url_data->publish_freq = frequency; + gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, TRUE); +} + +static gboolean +is_valid_url (const gchar *url) +{ + const gchar *p = url; + + if (strlen (url) == 0) { + return FALSE; + } + while (*p) { + if ((*p == '\\') || (*p == ' ')) { + return FALSE; + } + p++; + } + return TRUE; +} + +static void +url_editor_dialog_fb_url_activated (GtkEntry *url_entry, void *data) +{ + UrlDialogData *url_dlg_data = (UrlDialogData *) data; + + url_dlg_data->url_data->location = g_strdup (gtk_entry_get_text ((GtkEntry *) url_entry)); +} + +static void +url_editor_dialog_fb_url_changed (GtkEntry *url_entry, void *data) +{ + UrlDialogData *url_dlg_data = (UrlDialogData *) data; + DialogData *url_dialog = (DialogData *) url_dlg_data->url_dialog; + + const gchar *entry_contents; + GtkListStore *model; + GtkTreeIter iter; + gboolean valid; + + model = (GtkListStore *) gtk_tree_view_get_model (url_dialog->url_list); + + entry_contents = gtk_entry_get_text ((GtkEntry *) url_entry); + if (!is_valid_url (entry_contents)) { + gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, FALSE); + return; + } + /* duplicate check */ + valid = gtk_tree_model_get_iter_first ((GtkTreeModel *) model, &iter); + while (valid) { + gchar *url_name; + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + URL_LIST_LOCATION_COLUMN, &url_name, + -1); + + if (!strcasecmp (url_name, entry_contents)) { + gtk_widget_set_sensitive ((GtkWidget *) url_dlg_data->ok, FALSE); + return; + } + valid = gtk_tree_model_iter_next ((GtkTreeModel *) model, &iter); + } + /* valid and unique */ + gtk_widget_set_sensitive (GTK_WIDGET (url_dlg_data->ok), TRUE); + gtk_widget_grab_default (GTK_WIDGET (url_dlg_data->ok)); + gtk_entry_set_activates_default ((GtkEntry*) url_dlg_data->url_entry, + TRUE); +} + +static void url_editor_dialog_fb_ok_enable (GtkWidget *widget, void *data) { + UrlDialogData *url_dlg_data = (UrlDialogData *) data; + + gtk_widget_set_sensitive (GTK_WIDGET (url_dlg_data->ok), TRUE); +} diff --git a/calendar/gui/dialogs/url-editor-dialog.glade b/calendar/gui/dialogs/url-editor-dialog.glade new file mode 100644 index 0000000000..3685e69bd1 --- /dev/null +++ b/calendar/gui/dialogs/url-editor-dialog.glade @@ -0,0 +1,501 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> +<requires lib="gnome"/> + +<widget class="GtkDialog" id="url_editor"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Free/Busy Editor</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="cancel"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ok"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox9"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkFrame" id="frame2"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkHBox" id="hbox9"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label18"> + <property name="visible">True</property> + <property name="label" translatable="yes">URL:</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="url_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label26"> + <property name="visible">True</property> + <property name="label" translatable="yes">Free/Busy Publishing Location</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">6</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkVBox" id="vbox12"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="daily"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Daily</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="weekly"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Weekly</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">daily</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="user_publish"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">User Publishes</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">daily</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label25"> + <property name="visible">True</property> + <property name="label" translatable="yes">Publishing Frequency</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox11"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkFrame" id="frame4"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolled_window"> + <property name="height_request">150</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <placeholder/> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label28"> + <property name="visible">True</property> + <property name="label" translatable="yes">Calendars selected for publishing</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame3"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table1"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="label13"> + <property name="visible">True</property> + <property name="label" translatable="yes">Login name:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="label" translatable="yes">Password:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="username_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="password_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">False</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char" translatable="yes">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="remember_pw"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Remember password</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label27"> + <property name="visible">True</property> + <property name="label" translatable="yes">Authentication Credentials for HTTP Server</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/calendar/gui/dialogs/url-editor-dialog.h b/calendar/gui/dialogs/url-editor-dialog.h new file mode 100644 index 0000000000..a769ef6b80 --- /dev/null +++ b/calendar/gui/dialogs/url-editor-dialog.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Gary Ekker <gekker@novell.com> + * + * Copyright 2004, Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* + * UrlEditorDialog - a GtkObject which handles a libglade-loaded dialog + * to edit the calendar preference settings. + */ + +#ifndef _URL_EDITOR_DIALOG_H_ +#define _URL_EDITOR_DIALOG_H_ + +G_BEGIN_DECLS + +#include <gtk/gtk.h> +#include <glade/glade.h> + +#include "cal-prefs-dialog.h" +#include "widgets/misc/e-source-selector.h" + +struct _UrlDialogData { + /* Glade XML data */ + GladeXML *xml; + GtkWidget *url_editor; + GtkWidget *url_dialog; + + GtkEntry *url_entry; + GtkWidget *daily; + GtkWidget *weekly; + GtkWidget *user_publish; + + GtkWidget *scrolled_window; + + GtkEntry *username_entry; + GtkEntry *password_entry; + GtkWidget *remember_pw; + + GtkWidget *cancel; + GtkWidget *ok; + EPublishUri *url_data; +}; +typedef struct _UrlDialogData UrlDialogData; + +gboolean +url_editor_dialog_new (DialogData *dialog_data, EPublishUri *pub_uri); + +G_END_DECLS + +#endif /* _URL_EDITOR_DIALOG_H_ */ diff --git a/calendar/gui/e-cal-view.c b/calendar/gui/e-cal-view.c index 1aade80154..9ff5f500e3 100644 --- a/calendar/gui/e-cal-view.c +++ b/calendar/gui/e-cal-view.c @@ -41,6 +41,7 @@ #include "e-cal-view.h" #include "e-comp-editor-registry.h" #include "itip-utils.h" +#include "e-pub-utils.h" #include "dialogs/delete-comp.h" #include "dialogs/delete-error.h" #include "dialogs/event-editor.h" @@ -1127,34 +1128,7 @@ on_forward (GtkWidget *widget, gpointer user_data) static void on_publish (GtkWidget *widget, gpointer user_data) { - ECalendarView *cal_view; - icaltimezone *utc; - time_t start = time (NULL), end; - GList *comp_list = NULL, *client_list, *cl; - - cal_view = E_CALENDAR_VIEW (user_data); - - utc = icaltimezone_get_utc_timezone (); - start = time_day_begin_with_zone (start, utc); - end = time_add_week_with_zone (start, 6, utc); - - client_list = e_cal_model_get_client_list (cal_view->priv->model); - for (cl = client_list; cl != NULL; cl = cl->next) { - if (e_cal_get_free_busy ((ECal *) cl->data, NULL, start, end, &comp_list, NULL)) { - GList *l; - - for (l = comp_list; l; l = l->next) { - ECalComponent *comp = E_CAL_COMPONENT (l->data); - itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, (ECal *) cl->data, NULL); - - g_object_unref (comp); - } - - g_list_free (comp_list); - } - } - - g_list_free (client_list); + e_pub_publish (TRUE); } static void diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 1aade80154..9ff5f500e3 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -41,6 +41,7 @@ #include "e-cal-view.h" #include "e-comp-editor-registry.h" #include "itip-utils.h" +#include "e-pub-utils.h" #include "dialogs/delete-comp.h" #include "dialogs/delete-error.h" #include "dialogs/event-editor.h" @@ -1127,34 +1128,7 @@ on_forward (GtkWidget *widget, gpointer user_data) static void on_publish (GtkWidget *widget, gpointer user_data) { - ECalendarView *cal_view; - icaltimezone *utc; - time_t start = time (NULL), end; - GList *comp_list = NULL, *client_list, *cl; - - cal_view = E_CALENDAR_VIEW (user_data); - - utc = icaltimezone_get_utc_timezone (); - start = time_day_begin_with_zone (start, utc); - end = time_add_week_with_zone (start, 6, utc); - - client_list = e_cal_model_get_client_list (cal_view->priv->model); - for (cl = client_list; cl != NULL; cl = cl->next) { - if (e_cal_get_free_busy ((ECal *) cl->data, NULL, start, end, &comp_list, NULL)) { - GList *l; - - for (l = comp_list; l; l = l->next) { - ECalComponent *comp = E_CAL_COMPONENT (l->data); - itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, (ECal *) cl->data, NULL); - - g_object_unref (comp); - } - - g_list_free (comp_list); - } - } - - g_list_free (client_list); + e_pub_publish (TRUE); } static void diff --git a/calendar/gui/e-pub-utils.c b/calendar/gui/e-pub-utils.c new file mode 100644 index 0000000000..2d6cce62ec --- /dev/null +++ b/calendar/gui/e-pub-utils.c @@ -0,0 +1,310 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Evolution calendar Free/Busy utilities and types + * + * Copyright (C) 2004 Ximian, Inc. + * + * Author: Gary Ekker <gekker@novell.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <string.h> +#include <glib.h> +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> +#include <libedataserver/e-source.h> +#include <libedataserver/e-source-list.h> +#include <libecal/e-cal-time-util.h> +#include "calendar-config.h" +#include "common/authentication.h" +#include "itip-utils.h" +#include "e-pub-utils.h" + +void +e_pub_uri_from_xml (EPublishUri *uri, const gchar *xml) +{ + xmlDocPtr doc; + xmlNodePtr root, p; + xmlChar *location, *enabled, *frequency; + xmlChar *username, *password, *publish_time; + GSList *l = NULL; + + uri->location = NULL; + doc = xmlParseDoc ((char *)xml); + if (doc == NULL) { + uri->location = NULL; + return; + } + + root = doc->children; + if (strcmp (root->name, "uri") != 0) { + return; + } + location = xmlGetProp (root, "location"); + enabled = xmlGetProp (root, "enabled"); + frequency = xmlGetProp (root, "frequency"); + username = xmlGetProp (root, "username"); + password = xmlGetProp (root, "password"); + publish_time = xmlGetProp (root, "publish_time"); + + if (location != NULL) + uri->location = g_strdup (location); + if (enabled != NULL) + uri->enabled = atoi (enabled); + if (frequency != NULL) + uri->publish_freq = atoi (frequency); + if (username != NULL) + uri->username = g_strdup (username); + if (password != NULL) + uri->password = g_strdup (password); + if (publish_time != NULL) + uri->last_pub_time = g_strdup (publish_time); + + for (p = root->children; p != NULL; p = p->next) { + xmlChar *uid = xmlGetProp (p, "uid"); + + l = g_slist_append (l, uid); + } + uri->calendars = l; + + xmlFree(location); + xmlFree(enabled); + xmlFreeDoc(doc); + return; +} + +gchar * +e_pub_uri_to_xml (EPublishUri *uri) +{ + xmlDocPtr doc; + xmlNodePtr root; + gchar *enabled, *frequency; + GSList *cals = NULL; + xmlChar *xml_buffer; + char *returned_buffer; + int xml_buffer_size; + + g_return_val_if_fail (uri != NULL, NULL); + g_return_val_if_fail (uri->location != NULL, NULL); + + doc = xmlNewDoc ("1.0"); + + root = xmlNewDocNode (doc, NULL, "uri", NULL); + enabled = g_strdup_printf ("%d", uri->enabled); + frequency = g_strdup_printf ("%d", uri->publish_freq); + xmlSetProp (root, "location", uri->location); + xmlSetProp (root, "enabled", enabled); + xmlSetProp (root, "frequency", frequency); + xmlSetProp (root, "username", uri->username); + xmlSetProp (root, "password", uri->password); + xmlSetProp (root, "publish_time", uri->last_pub_time); + + for (cals = uri->calendars; cals != NULL; cals = cals->next) { + xmlNodePtr node; + + node = xmlNewChild (root, NULL, "source", NULL); + xmlSetProp (node, "uid", cals->data); + } + xmlDocSetRootElement (doc, root); + + xmlDocDumpMemory (doc, &xml_buffer, &xml_buffer_size); + xmlFreeDoc (doc); + + returned_buffer = g_malloc (xml_buffer_size + 1); + memcpy (returned_buffer, xml_buffer, xml_buffer_size); + returned_buffer [xml_buffer_size] = '\0'; + xmlFree (xml_buffer); + g_free (enabled); + + return returned_buffer; +} + +static gboolean +is_publish_time (EPublishUri *uri) { + icaltimezone *utc; + struct icaltimetype current_itt, adjust_itt; + + if (!uri->last_pub_time) { + utc = icaltimezone_get_utc_timezone (); + current_itt = icaltime_current_time_with_zone (utc); + uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt)); + return TRUE; + + } else { + if (strlen (uri->last_pub_time) == 0) { + uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt)); + return TRUE; + } + + utc = icaltimezone_get_utc_timezone (); + current_itt = icaltime_current_time_with_zone (utc); + adjust_itt = icaltime_from_string (uri->last_pub_time); + + switch (uri->publish_freq) { + case URI_PUBLISH_DAILY: + icaltime_adjust (&adjust_itt, 1, 0, 0, 0); + if (icaltime_compare_date_only (adjust_itt, current_itt ) < 0) { + uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt)); + return TRUE; + } + break; + case URI_PUBLISH_WEEKLY: + icaltime_adjust (&adjust_itt, 7, 0, 0, 0); + if (icaltime_compare_date_only (adjust_itt, current_itt ) < 0) { + uri->last_pub_time = g_strdup (icaltime_as_ical_string (current_itt)); + return TRUE; + } + break; + } + } + + return FALSE; +} + +static gboolean +just_published (gchar *last_pub_time) { + icaltimezone *utc; + struct icaltimetype pubtime_itt, adjust_itt; + + if (strlen (last_pub_time) != 0) { + utc = icaltimezone_get_utc_timezone (); + pubtime_itt = icaltime_from_string (last_pub_time); + adjust_itt = icaltime_current_time_with_zone (utc); + icaltime_adjust (&adjust_itt, 0, 0, 0, 3); + if (icaltime_compare_date_only (pubtime_itt, adjust_itt) < 0) + return TRUE; + } + + + return FALSE; +} + +void +e_pub_publish (gboolean publish) { + icaltimezone *utc; + time_t start = time (NULL), end; + GSList *uri_config_list, *l, *uri_list = NULL; + ESourceList *source_list; + GConfClient *gconf_client; + gboolean published = FALSE; + + gconf_client = gconf_client_get_default (); + source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/calendar/sources"); + + utc = icaltimezone_get_utc_timezone (); + start = time_day_begin_with_zone (start, utc); + end = time_add_week_with_zone (start, 6, utc); + + uri_config_list = calendar_config_get_free_busy (); + + for (l = uri_config_list; l != NULL; l = l->next) { + GSList *p =NULL; + EPublishUri *uri; + ECalComponent *clone = NULL; + gboolean cloned = FALSE; + ECal *client = NULL; + gchar *xml = (gchar *)uri_config_list->data; + + uri = g_new0 (EPublishUri, 1); + e_pub_uri_from_xml (uri, xml); + + /* kludge to safeguard against loop from gconf update */ + if (just_published (uri->last_pub_time)) + return; + + /* TODO: make sure we're online */ + /* skip this url if it isn't enabled or if it is manual */ + if (!uri->enabled) { + uri_config_list = g_slist_next (uri_config_list); + continue; + } + + if (!publish) { + /* a g_idle publish, make sure we are not set to user only */ + if (uri->publish_freq == URI_PUBLISH_USER) { + uri_config_list = g_slist_next (uri_config_list); + continue; + } + + /* If not is it time to publish again? */ + publish = is_publish_time (uri); + + } + + /* User published or config change */ + if (publish) { + /* We still need to set the last_pub_time */ + uri->last_pub_time = 0; + is_publish_time (uri); + + for (p = uri->calendars; p != NULL; p = p->next) { + GList *comp_list = NULL; + gchar *source_uid; + ESource * source; + + source_uid = g_strdup (p->data); + source = e_source_list_peek_source_by_uid (source_list, source_uid); + + client = auth_new_cal_from_uri (e_source_get_uri (source), E_CAL_SOURCE_TYPE_EVENT); + + if (!client) { + g_warning (G_STRLOC ": Could not publish Free/Busy: Calendar backend no longer exists"); + + continue; + } + + e_cal_open (client, TRUE, NULL); + + if (e_cal_get_free_busy ((ECal *) client, NULL, + start, end, + &comp_list, NULL)) { + GList *l; + + for (l = comp_list; l; l = l->next) { + ECalComponent *comp = E_CAL_COMPONENT (l->data); + + cloned = itip_publish_begin (comp, (ECal *) client, cloned, &clone); + g_object_unref (comp); + } + g_list_free (comp_list); + } + + g_object_unref (client); + + g_free (source_uid); + } + + published = itip_publish_comp ((ECal *) client, + uri->location, + uri->username, + uri->password, &clone); + + g_slist_free (p); + } + xml = e_pub_uri_to_xml (uri); + if (xml != NULL) { + uri_list = g_slist_append (uri_list, xml); + } + g_free (uri); + } + + if (published) { + /* Update gconf so we have the last_pub_time */ + calendar_config_set_free_busy (uri_list); + } + + g_slist_free (uri_config_list); + g_slist_free (uri_list); +} diff --git a/calendar/gui/e-pub-utils.h b/calendar/gui/e-pub-utils.h new file mode 100644 index 0000000000..03dcd97c98 --- /dev/null +++ b/calendar/gui/e-pub-utils.h @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Evolution calendar Free/Busy utilities and types + * + * Copyright (C) 2004 Ximian, Inc. + * + * Author: Gary Ekker <gekker@novell.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef E_CAL_FB_UTIL_H +#define E_CAL_FB_UTIL_H + +#include <glib.h> +#include <libxml/tree.h> + +G_BEGIN_DECLS + +enum publish_frequency{ + URI_PUBLISH_DAILY, + URI_PUBLISH_WEEKLY, + URI_PUBLISH_USER +}; + +static const int pub_frequency_type_map[] = { + URI_PUBLISH_DAILY, + URI_PUBLISH_WEEKLY, + URI_PUBLISH_USER, + -1 +}; + +struct _EPublishUri { + gint enabled; + gchar *location; + gint publish_freq; + gchar *username; + gchar *password; + GSList *calendars; + gchar *last_pub_time; +}; + +typedef struct _EPublishUri EPublishUri; + +void e_pub_uri_from_xml (EPublishUri *uri, const gchar *xml); +gchar *e_pub_uri_to_xml (EPublishUri *uri); +void e_pub_publish (gboolean publish) ; + +G_END_DECLS + +#endif diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c index 30e95dbcfe..b47232cc7f 100644 --- a/calendar/gui/itip-utils.c +++ b/calendar/gui/itip-utils.c @@ -37,6 +37,10 @@ #include <e-util/e-time-utils.h> #include <libecal/e-cal-time-util.h> #include <libecal/e-cal-util.h> +#include <libsoup/soup-session-async.h> +#include <libsoup/soup-message.h> +#include <libsoup/soup-uri.h> +#include "e-util/e-passwords.h" #include "calendar-config.h" #include "itip-utils.h" @@ -977,3 +981,220 @@ itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp, return retval; } +gboolean +itip_publish_begin (ECalComponent *pub_comp, ECal *client, + gboolean cloned, ECalComponent **clone) +{ + icalcomponent *icomp =NULL, *icomp_clone = NULL; + icalproperty *prop; + + if (e_cal_component_get_vtype (pub_comp) == E_CAL_COMPONENT_FREEBUSY) { + + if (!cloned) { + *clone = e_cal_component_clone (pub_comp); + cloned = TRUE; + } else { + + icomp = e_cal_component_get_icalcomponent (pub_comp); + icomp_clone = e_cal_component_get_icalcomponent (*clone); + for (prop = icalcomponent_get_first_property (icomp, + ICAL_FREEBUSY_PROPERTY); + prop != NULL; + prop = icalcomponent_get_next_property (icomp, + ICAL_FREEBUSY_PROPERTY)) + { + icalproperty *p; + + p = icalproperty_new_clone (prop); + icalcomponent_add_property (icomp_clone, p); + } + } + } + + return TRUE; +} + +static void +fb_sort (struct icalperiodtype *ipt, int fb_count) +{ + int i,j; + + if (ipt == NULL || fb_count == 0) + return; + + for (i = 0; i < fb_count-1; i++) { + for (j = i+1; j < fb_count; j++) { + struct icalperiodtype temp; + + if (icaltime_compare (ipt[i].start, ipt[j].start) < 0) + continue; + + if (icaltime_compare (ipt[i].start, ipt[j].start) == 0){ + if (icaltime_compare (ipt[i].end, + ipt[j].start) < 0) + continue; + } + temp = ipt[i]; + ipt[i] = ipt[j]; + ipt[j] = temp; + } + } +} + +static icalcomponent * +comp_fb_normalize (icalcomponent *icomp) +{ + icalcomponent *iclone; + icalproperty *prop, *p; + const char *uid, *comment; + struct icaltimetype itt; + int fb_count, i = 0, j; + struct icalperiodtype *ipt; + + iclone = icalcomponent_new (ICAL_VFREEBUSY_COMPONENT); + + prop = icalcomponent_get_first_property (icomp, + ICAL_ORGANIZER_PROPERTY); + p = icalproperty_new_clone (prop); + icalcomponent_add_property (iclone, p); + + itt = icalcomponent_get_dtstart (icomp); + icalcomponent_set_dtstart (iclone, itt); + + itt = icalcomponent_get_dtend (icomp); + icalcomponent_set_dtend (iclone, itt); + + fb_count = icalcomponent_count_properties (icomp, + ICAL_FREEBUSY_PROPERTY); + ipt = g_new0 (struct icalperiodtype, fb_count+1); + + for (prop = icalcomponent_get_first_property (icomp, + ICAL_FREEBUSY_PROPERTY); + prop != NULL; + prop = icalcomponent_get_next_property (icomp, + ICAL_FREEBUSY_PROPERTY)) + { + ipt[i] = icalproperty_get_freebusy (prop); + i++; + } + + fb_sort (ipt, fb_count); + + for (j = 0; j <= fb_count-1; j++) { + icalparameter *param; + + prop = icalproperty_new_freebusy (ipt[j]); + param = icalparameter_new_fbtype (ICAL_FBTYPE_BUSY); + icalproperty_add_parameter (prop, param); + icalcomponent_add_property (iclone, prop); + } + g_free (ipt); + + /* Should I strip this RFC 2446 says there must not be a UID + if the METHOD is PUBLISH?? */ + uid = icalcomponent_get_uid (icomp); + if (uid) + icalcomponent_set_uid (iclone, uid); + + itt = icaltime_from_timet_with_zone (time (NULL), FALSE, + icaltimezone_get_utc_timezone ()); + icalcomponent_set_dtstamp (iclone, itt); + + prop = icalcomponent_get_first_property (icomp, ICAL_URL_PROPERTY); + p = icalproperty_new_clone (prop); + icalcomponent_add_property (iclone, p); + + comment = icalcomponent_get_comment (icomp); + if (comment) + icalcomponent_set_comment (iclone, comment); + + for (prop = icalcomponent_get_first_property (icomp, ICAL_X_PROPERTY); + prop != NULL; + prop = icalcomponent_get_next_property (icomp, ICAL_X_PROPERTY)) + { + p = icalproperty_new_clone (prop); + icalcomponent_add_property (iclone, p); + } + + return iclone; + + g_object_unref (iclone); + return NULL; +} + +gboolean +itip_publish_comp (ECal *client, gchar *uri, gchar *username, + gchar *password, ECalComponent **pub_comp) +{ + icalcomponent *toplevel = NULL, *icalcomp = NULL; + icalcomponent *icomp = NULL; + SoupSession *session; + SoupMessage *msg; + SoupUri *real_uri; + char *ical_string; + char *prompt; + gboolean remember = FALSE; + + toplevel = e_cal_util_new_top_level (); + icalcomponent_set_method (toplevel, ICAL_METHOD_PUBLISH); + + e_cal_component_set_url (*pub_comp, uri); + + icalcomp = e_cal_component_get_icalcomponent (*pub_comp); + + icomp = comp_fb_normalize (icalcomp); + + icalcomponent_add_component (toplevel, icomp); + ical_string = icalcomponent_as_ical_string (toplevel); + + /* Publish the component */ + session = soup_session_async_new (); + + /* add username and password to the uri */ + if (strlen (password) == 0) { + prompt = g_strdup_printf (_("Enter the password for %s"), uri); + password = e_passwords_ask_password (_("Enter password"), + "Calendar", NULL, + prompt, TRUE, + E_PASSWORDS_DO_NOT_REMEMBER, + &remember, NULL); + + g_free (prompt); + } + + real_uri = soup_uri_new (uri); + if (!real_uri) { + g_warning (G_STRLOC ": Invalid URL: %s", uri); + g_object_unref (session); + return FALSE; + } + + real_uri->user = g_strdup (username); + real_uri->passwd = g_strdup (password); + + /* build the SOAP message */ + msg = soup_message_new_from_uri (SOUP_METHOD_PUT, real_uri); + if (!msg) { + g_warning (G_STRLOC ": Could not build SOAP message"); + g_object_unref (session); + return FALSE; + } + soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT); + soup_message_set_request (msg, "text/calendar", SOUP_BUFFER_USER_OWNED, + ical_string, strlen (ical_string)); + + /* send message to server */ + soup_session_send_message (session, msg); + if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { + g_warning(G_STRLOC ": Could not publish Free/Busy: %d: %s", + msg->status_code, + soup_status_get_phrase (msg->status_code)); + g_object_unref (session); + return FALSE; + } + + soup_uri_free (real_uri); + g_object_unref (session); + + return TRUE; +} diff --git a/calendar/gui/itip-utils.h b/calendar/gui/itip-utils.h index cf9dd37643..936adfec8e 100644 --- a/calendar/gui/itip-utils.h +++ b/calendar/gui/itip-utils.h @@ -31,5 +31,10 @@ const gchar *itip_strip_mailto (const gchar *address); gboolean itip_send_comp (ECalComponentItipMethod method, ECalComponent *comp, ECal *client, icalcomponent *zones); +gboolean itip_publish_comp (ECal *client, gchar* uri, gchar* username, + gchar* password, ECalComponent **pub_comp); + +gboolean itip_publish_begin (ECalComponent *pub_comp, ECal *client, + gboolean cloned, ECalComponent **clone); #endif |