aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--calendar/ChangeLog38
-rw-r--r--calendar/gui/apps_evolution_calendar.schemas.in.in10
-rw-r--r--calendar/gui/calendar-config-keys.h1
-rw-r--r--calendar/gui/calendar-config.c24
-rw-r--r--calendar/gui/calendar-config.h5
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.c18
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.glade552
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.h4
-rw-r--r--calendar/gui/e-meeting-store.c202
-rw-r--r--calendar/gui/e-meeting-store.h3
-rw-r--r--calendar/gui/e-meeting-time-sel.c54
-rw-r--r--calendar/gui/e-meeting-time-sel.h6
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">&lt;b&gt;Publishing&lt;/b&gt;</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">&lt;i&gt;%u and %d will be replaced by user and domain from the email address.&lt;/i&gt;</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">&lt;b&gt;Default Free/Busy Server&lt;/b&gt;</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;
};