diff options
-rw-r--r-- | calendar/ChangeLog | 38 | ||||
-rw-r--r-- | calendar/gui/apps_evolution_calendar.schemas.in.in | 10 | ||||
-rw-r--r-- | calendar/gui/calendar-config-keys.h | 1 | ||||
-rw-r--r-- | calendar/gui/calendar-config.c | 24 | ||||
-rw-r--r-- | calendar/gui/calendar-config.h | 5 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.c | 18 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.glade | 552 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.h | 4 | ||||
-rw-r--r-- | calendar/gui/e-meeting-store.c | 202 | ||||
-rw-r--r-- | calendar/gui/e-meeting-store.h | 3 | ||||
-rw-r--r-- | calendar/gui/e-meeting-time-sel.c | 54 | ||||
-rw-r--r-- | calendar/gui/e-meeting-time-sel.h | 6 |
12 files changed, 713 insertions, 204 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index bcd936c525..c951d54a2c 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,41 @@ +2004-12-18 James Bowes <bowes@cs.dal.ca> + + * gui/apps_evolution_calendar.schemas.in.in: Add schema for Free/Busy + template uri. + * gui/calendar-config-keys.h: + * gui/calendar-config.c: (calendar_config_get_free_busy_template), + (calendar_config_set_free_busy_template), + (calendar_config_add_notification_free_busy_template): + * gui/calendar-config.h: Functions to get, set and monitor the + Free/Busy template uri gconf setting. + * gui/dialogs/cal-prefs-dialog.c: (template_url_changed), + (setup_changes), (get_widgets), (show_fb_config): + * gui/dialogs/cal-prefs-dialog.glade: + * gui/dialogs/cal-prefs-dialog.h: Change 'Free/Busy Publish' tab to + 'Free/Busy'. Add an entry for setting the default Free/Busy uri. + Only change the gconf setting on 'focus out' event + * gui/e-meeting-store.c: (refresh_queue_remove): Check the hash using + the attendee's mailto: address, rather than the memory address of the + attendee object as the key. + (e_meeting_store_get_fb_uri), (e_meeting_store_set_fb_uri): Get and set + the EMeetingStore's Free/Busy template string. + (process_callbacks_main_thread), (process_callbacks): Process callbacks + in the main thread, so that widgets can be redrawn properly. + (replace_string): Utility function for replacing wildcards in the + default Free/Busy uri. + (ems_finalize), (ems_init), (freebusy_async), (refresh_busy_periods), + (refresh_queue_add), (e_meeting_store_refresh_busy_periods): Add the + ability to check for Free/Busy information from a default location, + if all else fails. + (start_async_read): Use gnome-vfs to read the Free/Busy information. + * gui/e-meeting-store.h: Add function prototypes for get and set fb_uri + * gui/e-meeting-time-sel.c: (e_meeting_time_selector_init), + (e_meeting_time_selector_destroy), (free_busy_timeout_refresh), + (free_busy_template_changed_cb): Watch for a change in the Free/Busy + template gconf setting, and check for new Free/Busy data if it occurs. + * gui/e-meeting-time-sel.h: Include variable for notification function + id on changes to the Free/Busy uri in the EMeetingTimeSelector . + 2004-12-17 Rodney Dawes <dobey@novell.com> * gui/alarm-notify/alarm-notify-dialog.c (an_minutes_update_label): diff --git a/calendar/gui/apps_evolution_calendar.schemas.in.in b/calendar/gui/apps_evolution_calendar.schemas.in.in index 5c9f1294a9..6be74dc8c1 100644 --- a/calendar/gui/apps_evolution_calendar.schemas.in.in +++ b/calendar/gui/apps_evolution_calendar.schemas.in.in @@ -367,5 +367,15 @@ <short>List of urls for free/busy publishing</short> </locale> </schema> + + <schema> + <key>/schemas/apps/evolution/calendar/publish/template</key> + <applyto>/apps/evolution/calendar/publish/template</applyto> + <owner>evolution-calendar</owner> + <type>string</type> + <locale name="C"> + <short>The url template to use as a free/busy data fallback</short> + </locale> + </schema> </schemalist> </gconfschemafile> diff --git a/calendar/gui/calendar-config-keys.h b/calendar/gui/calendar-config-keys.h index bdcad1476e..d3be9673e5 100644 --- a/calendar/gui/calendar-config-keys.h +++ b/calendar/gui/calendar-config-keys.h @@ -72,6 +72,7 @@ G_BEGIN_DECLS /* Free/Busy settings */ #define CALENDAR_CONFIG_PUBLISH CALENDAR_CONFIG_PREFIX"/publish/uris" +#define CALENDAR_CONFIG_TEMPLATE CALENDAR_CONFIG_PREFIX"/publish/template" G_END_DECLS diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c index f82fe344f7..adbbf21b0c 100644 --- a/calendar/gui/calendar-config.c +++ b/calendar/gui/calendar-config.c @@ -1063,3 +1063,27 @@ calendar_config_set_free_busy (GSList *url_list) gconf_client_set_list (config, CALENDAR_CONFIG_PUBLISH, GCONF_VALUE_STRING, url_list, NULL); } + +gchar * +calendar_config_get_free_busy_template (void) +{ + return gconf_client_get_string (config, CALENDAR_CONFIG_TEMPLATE, NULL); +} + +void +calendar_config_set_free_busy_template (const gchar *template) +{ + gconf_client_set_string (config, CALENDAR_CONFIG_TEMPLATE, template, NULL); +} + +guint +calendar_config_add_notification_free_busy_template (GConfClientNotifyFunc func, + gpointer data) +{ + guint id; + + id = gconf_client_notify_add (config, CALENDAR_CONFIG_TEMPLATE, func, data, + NULL, NULL); + + return id; +} diff --git a/calendar/gui/calendar-config.h b/calendar/gui/calendar-config.h index e2dc4405b8..cba2c7bcd7 100644 --- a/calendar/gui/calendar-config.h +++ b/calendar/gui/calendar-config.h @@ -206,6 +206,11 @@ void calendar_config_set_default_reminder_units (CalUnits units); GSList * calendar_config_get_free_busy (void); void calendar_config_set_free_busy (GSList * url_list); +gchar *calendar_config_get_free_busy_template (void); +void calendar_config_set_free_busy_template (const gchar *template); +guint calendar_config_add_notification_free_busy_template (GConfClientNotifyFunc func, + gpointer data); + /* Convenience functions to configure common properties of ECalendar, EDateEdit & ECalendarTable widgets, and the ECellDateEdit ETable cell. */ void calendar_config_configure_e_calendar (ECalendar *cal); diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c index 6c5062a881..79a825ef73 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.c +++ b/calendar/gui/dialogs/cal-prefs-dialog.c @@ -371,6 +371,14 @@ url_list_changed (DialogData *dialog_data) } static void +template_url_changed (GtkEntry *entry, DialogData *dialog_data) +{ + calendar_config_set_free_busy_template (gtk_entry_get_text (entry)); + + return FALSE; +} + +static void setup_changes (DialogData *dialog_data) { int i; @@ -412,6 +420,8 @@ setup_changes (DialogData *dialog_data) G_CALLBACK (default_reminder_interval_changed), dialog_data); g_signal_connect (GTK_OPTION_MENU (dialog_data->default_reminder_units)->menu, "selection-done", G_CALLBACK (default_reminder_units_changed), dialog_data); + + g_signal_connect (dialog_data->template_url, "changed", G_CALLBACK (template_url_changed), dialog_data); } /* Gets the widgets from the XML file and returns if they are all available. @@ -463,6 +473,8 @@ get_widgets (DialogData *data) data->url_enable = GW ("url_enable"); data->url_list = GTK_TREE_VIEW (GW ("url_list")); + data->template_url = GW("template_url"); + #undef GW return (data->page @@ -859,6 +871,7 @@ show_fb_config (DialogData *dialog_data) GSList *url_config_list = NULL; GtkListStore *model; GtkTreeIter iter; + gchar *template_url; model = (GtkListStore *) gtk_tree_view_get_model (dialog_data->url_list); gtk_list_store_clear (model); @@ -910,6 +923,11 @@ show_fb_config (DialogData *dialog_data) g_slist_foreach (url_config_list, (GFunc) g_free, NULL); g_slist_free (url_config_list); + + template_url = calendar_config_get_free_busy_template (); + gtk_entry_set_text (GTK_ENTRY (dialog_data->template_url), template_url); + + g_free (template_url); } /* Shows the current task list settings in the dialog */ diff --git a/calendar/gui/dialogs/cal-prefs-dialog.glade b/calendar/gui/dialogs/cal-prefs-dialog.glade index f2c48c19a2..95c5c9887f 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.glade +++ b/calendar/gui/dialogs/cal-prefs-dialog.glade @@ -1520,247 +1520,433 @@ </child> <child> - <widget class="GtkHBox" id="hbox20"> + <widget class="GtkVBox" id="vbox17"> <property name="border_width">12</property> <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> + <property name="spacing">12</property> <child> - <widget class="GtkVBox" id="vbox15"> + <widget class="GtkFrame" id="frame2"> <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">6</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> <child> - <widget class="GtkVButtonBox" id="vbuttonbox3"> + <widget class="GtkAlignment" id="alignment8"> <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_START</property> - <property name="spacing">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">12</property> + <property name="bottom_padding">0</property> + <property name="left_padding">12</property> + <property name="right_padding">0</property> <child> - <widget class="GtkButton" id="url_add"> + <widget class="GtkHBox" id="hbox20"> <property name="visible">True</property> - <property name="can_default">True</property> - <property name="can_focus">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> <child> - <widget class="GtkAlignment" id="alignment5"> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> <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> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">0</property> - <property name="right_padding">0</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">6</property> <child> - <widget class="GtkHBox" id="hbox22"> + <widget class="GtkVButtonBox" id="vbuttonbox3"> <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">2</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">6</property> <child> - <widget class="GtkImage" id="image1"> + <widget class="GtkButton" id="url_add"> <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> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</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> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">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> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> </child> <child> - <widget class="GtkLabel" id="labeladd"> + <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">_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> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox23"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-properties</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="label47"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Edit</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> - <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="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - - <child> - <widget class="GtkAlignment" id="alignment6"> - <property name="visible">True</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">0</property> - <property name="right_padding">0</property> - - <child> - <widget class="GtkHBox" id="hbox23"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">2</property> <child> - <widget class="GtkImage" id="image2"> + <widget class="GtkButton" id="url_remove"> <property name="visible">True</property> - <property name="stock">gtk-properties</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> + <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> + <property name="focus_on_click">True</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="label47"> + <widget class="GtkButton" id="url_enable"> <property name="visible">True</property> - <property name="label" translatable="yes">_Edit</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="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> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</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> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox4"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">3</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="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> </child> + </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> - <property name="focus_on_click">True</property> - </widget> - </child> - - <child> - <widget class="GtkButton" id="url_enable"> - <property name="visible">True</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> - <property name="focus_on_click">True</property> - </widget> - </child> + <child> + <widget class="GtkLabel" id="label60"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Publishing</b></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> + <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> + + <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_NONE</property> <child> - <widget class="GtkVButtonBox" id="vbuttonbox4"> + <widget class="GtkAlignment" id="alignment7"> <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_START</property> - <property name="spacing">3</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">12</property> + <property name="bottom_padding">0</property> + <property name="left_padding">12</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkVBox" id="vbox18"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox30"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">12</property> + + <child> + <widget class="GtkLabel" id="label61"> + <property name="visible">True</property> + <property name="label" translatable="yes">Template:</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="GtkEntry" id="template_url"> + <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">*</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> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label62"> + <property name="visible">True</property> + <property name="label" translatable="yes"><i>%u and %d will be replaced by user and domain from the email address.</i></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.49</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> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> </child> <child> - <widget class="GtkLabel" id="label46"> + <widget class="GtkLabel" id="label59"> <property name="visible">True</property> - <property name="label" translatable="yes"></property> + <property name="label" translatable="yes"><b>Default Free/Busy Server</b></property> <property name="use_underline">False</property> - <property name="use_markup">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> @@ -1770,16 +1956,14 @@ <property name="ypad">0</property> </widget> <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <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> + <property name="fill">True</property> </packing> </child> </widget> @@ -1792,7 +1976,7 @@ <child> <widget class="GtkLabel" id="label42"> <property name="visible">True</property> - <property name="label" translatable="yes">Free/Busy Publishing</property> + <property name="label" translatable="yes">Free/Busy</property> <property name="use_underline">True</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_CENTER</property> diff --git a/calendar/gui/dialogs/cal-prefs-dialog.h b/calendar/gui/dialogs/cal-prefs-dialog.h index 8905cb618b..5c92570d37 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.h +++ b/calendar/gui/dialogs/cal-prefs-dialog.h @@ -83,7 +83,9 @@ struct _DialogData { gboolean url_editor; GtkWidget* url_editor_dlg; guint destroyed : 1; - + + /* widgets for the Free/Busy template */ + GtkWidget *template_url; /* Other page options */ GtkWidget *confirm_delete; diff --git a/calendar/gui/e-meeting-store.c b/calendar/gui/e-meeting-store.c index c4eafd34a9..b1082cb02b 100644 --- a/calendar/gui/e-meeting-store.c +++ b/calendar/gui/e-meeting-store.c @@ -48,12 +48,18 @@ struct _EMeetingStorePrivate { ECal *client; icaltimezone *zone; + char *fb_uri; + EBook *ebook; GPtrArray *refresh_queue; GHashTable *refresh_data; GMutex *mutex; guint refresh_idle_id; + + guint callback_idle_id; + guint num_threads; + GAsyncQueue *async_queue; }; #define BUF_SIZE 1024 @@ -78,6 +84,8 @@ struct _EMeetingStoreQueueData { static GObjectClass *parent_class = NULL; +static void start_async_read (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data); + static void start_addressbook_server (EMeetingStore *store) { @@ -553,9 +561,8 @@ refresh_queue_remove (EMeetingStore *store, EMeetingAttendee *attendee) priv = store->priv; /* Free the queue data */ - qdata = g_hash_table_lookup (priv->refresh_data, attendee); + qdata = g_hash_table_lookup (priv->refresh_data, itip_strip_mailto (e_meeting_attendee_get_address (attendee))); if (qdata) { - g_hash_table_remove (priv->refresh_data, attendee); g_mutex_lock (priv->mutex); g_hash_table_remove (priv->refresh_data, itip_strip_mailto (e_meeting_attendee_get_address (attendee))); g_mutex_unlock (priv->mutex); @@ -596,7 +603,14 @@ ems_finalize (GObject *obj) if (priv->refresh_idle_id) g_source_remove (priv->refresh_idle_id); + if (priv->callback_idle_id) + g_source_remove (priv->callback_idle_id); + + g_free (priv->fb_uri); + g_mutex_free (priv->mutex); + + g_async_queue_unref (priv->async_queue); g_free (priv); @@ -625,12 +639,16 @@ ems_init (EMeetingStore *store) priv->attendees = g_ptr_array_new (); priv->zone = calendar_config_get_icaltimezone (); + + priv->fb_uri = calendar_config_get_free_busy_template (); priv->refresh_queue = g_ptr_array_new (); priv->refresh_data = g_hash_table_new (g_str_hash, g_str_equal); priv->mutex = g_mutex_new (); + priv->async_queue = g_async_queue_new (); + start_addressbook_server (store); } @@ -708,6 +726,23 @@ e_meeting_store_set_zone (EMeetingStore *store, icaltimezone *zone) store->priv->zone = zone; } +gchar * +e_meeting_store_get_fb_uri (EMeetingStore *store) +{ + g_return_val_if_fail (E_IS_MEETING_STORE (store), NULL); + + return g_strdup (store->priv->fb_uri); +} + +void +e_meeting_store_set_fb_uri (EMeetingStore *store, const gchar *fb_uri) +{ + g_return_if_fail (E_IS_MEETING_STORE (store)); + + g_free (store->priv->fb_uri); + store->priv->fb_uri = g_strdup (fb_uri); +} + static void attendee_changed_cb (EMeetingAttendee *attendee, gpointer data) { @@ -947,24 +982,60 @@ find_zone (icalproperty *ip, icalcomponent *tz_top_level) return NULL; } +typedef struct { + EMeetingStoreRefreshCallback call_back; + gpointer *data; +} QueueCbData; + +/* Process the callbacks in the main thread. Avoids widget redrawing issues. */ +static gboolean +process_callbacks_main_thread (EMeetingStore *store) +{ + EMeetingStorePrivate *priv; + QueueCbData *aqueue_data; + gboolean threads_done = FALSE; + + priv = store->priv; + + g_mutex_lock (priv->mutex); + if (priv->num_threads == 0) { + threads_done = TRUE; + priv->callback_idle_id = 0; + } + g_mutex_unlock (priv->mutex); + + while ((aqueue_data = g_async_queue_try_pop (priv->async_queue)) != NULL) { + aqueue_data->call_back (aqueue_data->data); + + g_free (aqueue_data); + } + + return !threads_done; +} + static void process_callbacks (EMeetingStoreQueueData *qdata) { EMeetingStore *store; int i; + store = qdata->store; + for (i = 0; i < qdata->call_backs->len; i++) { - EMeetingStoreRefreshCallback call_back; - gpointer *data; + QueueCbData *aqueue_data = g_new0 (QueueCbData, 1); - call_back = g_ptr_array_index (qdata->call_backs, i); - data = g_ptr_array_index (qdata->data, i); + aqueue_data->call_back = g_ptr_array_index (qdata->call_backs, i); + aqueue_data->data = g_ptr_array_index (qdata->data, i); - call_back (data); + g_async_queue_push (store->priv->async_queue, aqueue_data); } - store = qdata->store; + g_mutex_lock (store->priv->mutex); + store->priv->num_threads--; + g_mutex_unlock (store->priv->mutex); + refresh_queue_remove (qdata->store, qdata->attendee); + g_async_queue_unref (store->priv->async_queue); g_object_unref (store); } @@ -1116,22 +1187,45 @@ process_free_busy (EMeetingStoreQueueData *qdata, char *text) process_callbacks (qdata); } +/* + * Replace all instances of from_value in string with to_value + * In the returned newly allocated string. +*/ +static gchar * +replace_string (gchar *string, gchar *from_value, gchar *to_value) +{ + gchar *replaced; + gchar **split_uri; + + split_uri = g_strsplit (string, from_value, 0); + replaced = g_strjoinv (to_value, split_uri); + g_strfreev (split_uri); + + return replaced; +} + typedef struct { ECal *client; time_t startt; time_t endt; GList *users; GList *fb_data; + char *fb_uri; + char *email; EMeetingAttendee *attendee; EMeetingStoreQueueData *qdata; } FreeBusyAsyncData; +#define USER_SUB "%u" +#define DOMAIN_SUB "%d" + static gboolean freebusy_async (gpointer data) { FreeBusyAsyncData *fbd = data; EMeetingAttendee *attendee = fbd->attendee; - + gchar *default_fb_uri; + if (fbd->client) { e_cal_get_free_busy (fbd->client, fbd->users, fbd->startt, fbd->endt, &(fbd->fb_data), NULL); @@ -1145,22 +1239,53 @@ freebusy_async (gpointer data) comp_str = e_cal_component_get_as_string (comp); process_free_busy (fbd->qdata, comp_str); g_free (comp_str); + + return TRUE; } - return TRUE; } - /* Look for fburl's of attendee with no free busy info on server */ if (!e_meeting_attendee_is_set_address (attendee)) { process_callbacks (fbd->qdata); return TRUE; } + + + /* Check for free busy info on the default server */ + default_fb_uri = g_strdup (fbd->fb_uri); + + if (default_fb_uri != NULL || !g_str_equal (default_fb_uri, "")) { + GnomeVFSAsyncHandle *handle; + gchar *tmp_fb_uri; + gchar **split_email; + + split_email = g_strsplit (fbd->email, "@", 2); + + tmp_fb_uri = replace_string (default_fb_uri, USER_SUB, split_email[0]); + g_free (default_fb_uri); + default_fb_uri = replace_string (tmp_fb_uri, DOMAIN_SUB, split_email[1]); + + gnome_vfs_async_open (&handle, default_fb_uri, GNOME_VFS_OPEN_READ, + GNOME_VFS_PRIORITY_DEFAULT, start_async_read, + fbd->qdata); + + g_free (tmp_fb_uri); + g_strfreev (split_email); + g_free (default_fb_uri); + } else { + process_callbacks (fbd->qdata); + } + return TRUE; } +#undef USER_SUB +#undef DOMAIN_SUB + + static gboolean refresh_busy_periods (gpointer data) { @@ -1202,13 +1327,16 @@ refresh_busy_periods (gpointer data) fbd = g_new0 (FreeBusyAsyncData, 1); fbd->client = priv->client; + fbd->attendee = attendee; fbd->users = NULL; fbd->fb_data = NULL; + fbd->qdata = qdata; + fbd->fb_uri = priv->fb_uri; + fbd->email = g_strdup (itip_strip_mailto (e_meeting_attendee_get_address (attendee))); /* Check the server for free busy data */ if (priv->client) { struct icaltimetype itt; - const char *user; itt = icaltime_null_time (); itt.year = g_date_year (&qdata->start.date); @@ -1226,19 +1354,36 @@ refresh_busy_periods (gpointer data) itt.minute = qdata->end.minute; fbd->endt = icaltime_as_timet_with_zone (itt, priv->zone); fbd->qdata = qdata; - fbd->attendee = attendee; - user = itip_strip_mailto (e_meeting_attendee_get_address (attendee)); - fbd->users = g_list_append (fbd->users, g_strdup (user)); + fbd->users = g_list_append (fbd->users, g_strdup (fbd->email)); } - + + + g_async_queue_ref (priv->async_queue); + + g_mutex_lock (store->priv->mutex); + store->priv->num_threads++; + g_mutex_unlock (store->priv->mutex); + thread = g_thread_create ((GThreadFunc) freebusy_async, fbd, FALSE, &error); if (!thread) { /* do clean up stuff here */ g_list_foreach (fbd->users, (GFunc)g_free, NULL); g_list_free (fbd->users); + g_free (fbd->email); + priv->refresh_idle_id = 0; + + g_async_queue_unref (priv->async_queue); + + g_mutex_lock (store->priv->mutex); + store->priv->num_threads--; + g_mutex_unlock (store->priv->mutex); + return FALSE; + } else if (priv->callback_idle_id == 0) { + priv->callback_idle_id = g_idle_add (process_callbacks_main_thread, + store); } return TRUE; } @@ -1256,16 +1401,18 @@ refresh_queue_add (EMeetingStore *store, int row, int i; priv = store->priv; - + attendee = g_ptr_array_index (priv->attendees, row); if ((attendee == NULL) || !strcmp (itip_strip_mailto (e_meeting_attendee_get_address (attendee)), "")) return; + /* check the queue if the attendee is already in there*/ for (i = 0; i < priv->refresh_queue->len; i++) { if (attendee == g_ptr_array_index (priv->refresh_queue, i)) return; + if (!strcmp (e_meeting_attendee_get_address (attendee), e_meeting_attendee_get_address (g_ptr_array_index (priv->refresh_queue, i)))) - return; + return; } g_mutex_lock (priv->mutex); @@ -1343,6 +1490,24 @@ async_read (GnomeVFSAsyncHandle *handle, gnome_vfs_async_read (handle, qdata->buffer, buf_size, async_read, qdata); } +static void +start_async_read (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + gpointer data) +{ + EMeetingStoreQueueData *qdata = data; + GnomeVFSFileSize buf_size = BUF_SIZE - 1; + + if (result != GNOME_VFS_OK) { + g_warning ("Unable to access free/busy url: %s", + gnome_vfs_result_to_string (result)); + process_callbacks (qdata); + return; + } + + gnome_vfs_async_read (handle, qdata->buffer, buf_size, async_read, qdata); +} + void e_meeting_store_refresh_all_busy_periods (EMeetingStore *store, EMeetingTime *start, @@ -1370,4 +1535,3 @@ e_meeting_store_refresh_busy_periods (EMeetingStore *store, refresh_queue_add (store, row, start, end, call_back, data); } - diff --git a/calendar/gui/e-meeting-store.h b/calendar/gui/e-meeting-store.h index 4bdcec40fa..8d18126422 100644 --- a/calendar/gui/e-meeting-store.h +++ b/calendar/gui/e-meeting-store.h @@ -78,6 +78,9 @@ void e_meeting_store_set_e_cal (EMeetingStore *im, ECal *client); icaltimezone *e_meeting_store_get_zone (EMeetingStore *im); void e_meeting_store_set_zone (EMeetingStore *im, icaltimezone *zone); +gchar *e_meeting_store_get_fb_uri (EMeetingStore *im); +void e_meeting_store_set_fb_uri (EMeetingStore *im, const gchar *fb_uri); + void e_meeting_store_add_attendee (EMeetingStore *im, EMeetingAttendee *ia); EMeetingAttendee *e_meeting_store_add_attendee_with_defaults (EMeetingStore *im); diff --git a/calendar/gui/e-meeting-time-sel.c b/calendar/gui/e-meeting-time-sel.c index 0ae13bf07f..5f92ab6a63 100644 --- a/calendar/gui/e-meeting-time-sel.c +++ b/calendar/gui/e-meeting-time-sel.c @@ -207,6 +207,9 @@ static void row_inserted_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter static void row_changed_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); static void row_deleted_cb (GtkTreeModel *model, GtkTreePath *path, gpointer data); +static void free_busy_template_changed_cb (GConfClient *client, guint cnxn_id, + GConfEntry *entry, gpointer user_data); + G_DEFINE_TYPE (EMeetingTimeSelector, e_meeting_time_selector, GTK_TYPE_TABLE); static void @@ -252,6 +255,12 @@ e_meeting_time_selector_init (EMeetingTimeSelector * mts) mts->dragging_position = E_MEETING_TIME_SELECTOR_POS_NONE; mts->list_view = NULL; + + mts->fb_uri_not = + calendar_config_add_notification_free_busy_template ((GConfClientNotifyFunc) free_busy_template_changed_cb, + mts); + + mts->fb_refresh_not = 0; } @@ -825,6 +834,12 @@ e_meeting_time_selector_destroy (GtkObject *object) mts->display_top = NULL; mts->display_main = NULL; + + calendar_config_remove_notification (mts->fb_uri_not); + + if (mts->fb_refresh_not != 0) { + g_source_remove (mts->fb_refresh_not); + } if (GTK_OBJECT_CLASS (e_meeting_time_selector_parent_class)->destroy) (*GTK_OBJECT_CLASS (e_meeting_time_selector_parent_class)->destroy)(object); @@ -2877,3 +2892,42 @@ row_deleted_cb (GtkTreeModel *model, GtkTreePath *path, gpointer data) gtk_widget_queue_draw (mts->display_main); } + +#define REFRESH_PAUSE 5000 + +static gboolean +free_busy_timeout_refresh (gpointer data) +{ + char *fb_uri; + + EMeetingTimeSelector *mts = E_MEETING_TIME_SELECTOR (data); + + fb_uri = calendar_config_get_free_busy_template (); + e_meeting_store_set_fb_uri (mts->model, fb_uri); + g_free (fb_uri); + + /* Update all free/busy info, so we use the new template uri */ + e_meeting_time_selector_refresh_free_busy (mts, 0, TRUE); + + mts->fb_refresh_not = 0; + + return FALSE; +} + +static void +free_busy_template_changed_cb (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer data) +{ + EMeetingTimeSelector *mts = E_MEETING_TIME_SELECTOR (data); + + /* Wait REFRESH_PAUSE before refreshing, using the latest uri value */ + if (mts->fb_refresh_not != 0) { + g_source_remove (mts->fb_refresh_not); + } + + mts->fb_refresh_not = g_timeout_add (REFRESH_PAUSE, + free_busy_timeout_refresh, + data); +} diff --git a/calendar/gui/e-meeting-time-sel.h b/calendar/gui/e-meeting-time-sel.h index 7ff6811657..b3ff09f18f 100644 --- a/calendar/gui/e-meeting-time-sel.h +++ b/calendar/gui/e-meeting-time-sel.h @@ -252,6 +252,12 @@ struct _EMeetingTimeSelector /* This is used to determine the delay between scrolls. */ gint scroll_count; + + /* The notification function id for Free/Busy template uri changes */ + guint fb_uri_not; + + /* The notification function id for Free/Busy refreshes */ + gboolean fb_refresh_not; }; |