diff options
-rw-r--r-- | plugins/itip-formatter/.cvsignore | 6 | ||||
-rw-r--r-- | plugins/itip-formatter/ChangeLog | 4 | ||||
-rw-r--r-- | plugins/itip-formatter/Makefile.am | 14 | ||||
-rw-r--r-- | plugins/itip-formatter/itip-formatter.c | 275 | ||||
-rw-r--r-- | plugins/itip-formatter/itip-view.c | 720 | ||||
-rw-r--r-- | plugins/itip-formatter/itip-view.h | 102 | ||||
-rw-r--r-- | plugins/itip-formatter/org-gnome-itip-formatter.eplug.in | 14 |
7 files changed, 1135 insertions, 0 deletions
diff --git a/plugins/itip-formatter/.cvsignore b/plugins/itip-formatter/.cvsignore new file mode 100644 index 0000000000..76bd16c42d --- /dev/null +++ b/plugins/itip-formatter/.cvsignore @@ -0,0 +1,6 @@ +.deps +.libs +Makefile +Makefile.in +*.eplug +backup
\ No newline at end of file diff --git a/plugins/itip-formatter/ChangeLog b/plugins/itip-formatter/ChangeLog new file mode 100644 index 0000000000..c2fbae2bad --- /dev/null +++ b/plugins/itip-formatter/ChangeLog @@ -0,0 +1,4 @@ +2004-12-22 JP Rosevear <jpr@novell.com> + + * Initial checkin of new itip formatter + diff --git a/plugins/itip-formatter/Makefile.am b/plugins/itip-formatter/Makefile.am new file mode 100644 index 0000000000..418d43830c --- /dev/null +++ b/plugins/itip-formatter/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = \ + -I$(top_srcdir) \ + $(EVOLUTION_MAIL_CFLAGS) \ + $(EVOLUTION_CALENDAR_CFLAGS) + +@EVO_PLUGIN_RULE@ + +plugin_DATA = org-gnome-itip-formatter.eplug +plugin_LTLIBRARIES = liborg-gnome-itip-formatter.la + +liborg_gnome_itip_formatter_la_SOURCES = itip-formatter.c itip-view.c itip-view.h +liborg_gnome_itip_formatter_la_LDFLAGS = -module -avoid-version + +EXTRA_DIST = org-gnome-itip-formatter.eplug.in
\ No newline at end of file diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c new file mode 100644 index 0000000000..c16cc24826 --- /dev/null +++ b/plugins/itip-formatter/itip-formatter.c @@ -0,0 +1,275 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: JP Rosevear <jpr@novell.com> + * + * Copyright 2004 Novell, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <libgnome/gnome-i18n.h> +#include <gconf/gconf-client.h> +#include <camel/camel-stream.h> +#include <camel/camel-stream-mem.h> +#include <camel/camel-medium.h> +#include <camel/camel-mime-message.h> +#include <libecal/e-cal.h> +#include <libecal/e-cal-time-util.h> +#include <gtkhtml/gtkhtml-embedded.h> +#include <mail/em-format-hook.h> +#include <mail/em-format-html.h> +#include <e-util/e-account-list.h> +#include <e-util/e-icon-factory.h> +#include <calendar/gui/itip-utils.h> +#include "itip-view.h" + +#define CLASSID "itip://" + +void format_itip (EPlugin *ep, EMFormatHookTarget *target); + +typedef struct { + EMFormatHTMLPObject pobject; + + GtkWidget *view; + + ESourceList *source_lists[E_CAL_SOURCE_TYPE_LAST]; + GHashTable *ecals[E_CAL_SOURCE_TYPE_LAST]; + + ECal *current_ecal; + ECalSourceType type; + + char action; + gboolean rsvp; + + GtkWidget *ok; + GtkWidget *hbox; + GtkWidget *vbox; + + char *vcalendar; + ECalComponent *comp; + icalcomponent *main_comp; + icalcomponent *ical_comp; + icalcomponent *top_level; + icalcompiter iter; + icalproperty_method method; + + int current; + int total; + + gchar *calendar_uid; + + EAccountList *accounts; + + gchar *from_address; + gchar *delegator_address; + gchar *delegator_name; + gchar *my_address; + gint view_only; +} FormatItipPObject; + +static icalcomponent * +get_next (icalcompiter *iter) +{ + icalcomponent *ret = NULL; + icalcomponent_kind kind; + + do { + icalcompiter_next (iter); + ret = icalcompiter_deref (iter); + if (ret == NULL) + break; + kind = icalcomponent_isa (ret); + } while (ret != NULL + && kind != ICAL_VEVENT_COMPONENT + && kind != ICAL_VTODO_COMPONENT + && kind != ICAL_VFREEBUSY_COMPONENT); + + return ret; +} + +static void +extract_itip_data (FormatItipPObject *pitip) +{ + CamelDataWrapper *content; + CamelStream *mem; + icalproperty *prop; + icalcomponent_kind kind = ICAL_NO_COMPONENT; + icalcomponent *tz_comp; + icalcompiter tz_iter; + +/* FIXME try and match sender with organizer/attendee/sentby? + pd->from_address = camel_address_encode ((CamelAddress *)from); + g_message ("Detected from address %s", pd->from_address); +*/ + + content = camel_medium_get_content_object ((CamelMedium *) pitip->pobject.part); + mem = camel_stream_mem_new (); + camel_data_wrapper_write_to_stream (content, mem); + + pitip->vcalendar = g_strndup (((CamelStreamMem *) mem)->buffer->data, ((CamelStreamMem *) mem)->buffer->len); + + /* FIXME unref the content object as well? */ + camel_object_unref (mem); + + pitip->top_level = e_cal_util_new_top_level (); + + pitip->main_comp = icalparser_parse_string (pitip->vcalendar); + if (pitip->main_comp == NULL) { +// write_error_html (itip, _("The attachment does not contain a valid calendar message")); + return; + } + + prop = icalcomponent_get_first_property (pitip->main_comp, ICAL_METHOD_PROPERTY); + if (prop == NULL) { + pitip->method = ICAL_METHOD_PUBLISH; + } else { + pitip->method = icalproperty_get_method (prop); + } + + tz_iter = icalcomponent_begin_component (pitip->main_comp, ICAL_VTIMEZONE_COMPONENT); + while ((tz_comp = icalcompiter_deref (&tz_iter)) != NULL) { + icalcomponent *clone; + + clone = icalcomponent_new_clone (tz_comp); + icalcomponent_add_component (pitip->top_level, clone); + + icalcompiter_next (&tz_iter); + } + + pitip->iter = icalcomponent_begin_component (pitip->main_comp, ICAL_ANY_COMPONENT); + pitip->ical_comp = icalcompiter_deref (&pitip->iter); + if (pitip->ical_comp != NULL) { + kind = icalcomponent_isa (pitip->ical_comp); + if (kind != ICAL_VEVENT_COMPONENT + && kind != ICAL_VTODO_COMPONENT + && kind != ICAL_VFREEBUSY_COMPONENT) + pitip->ical_comp = get_next (&pitip->iter); + } + + if (pitip->ical_comp == NULL) { +// write_error_html (itip, _("The attachment has no viewable calendar items")); + return; + } + + pitip->total = icalcomponent_count_components (pitip->main_comp, ICAL_VEVENT_COMPONENT); + pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VTODO_COMPONENT); + pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VFREEBUSY_COMPONENT); + + if (pitip->total > 0) + pitip->current = 1; + else + pitip->current = 0; + + pitip->comp = e_cal_component_new (); + if (!e_cal_component_set_icalcomponent (pitip->comp, pitip->ical_comp)) { +// write_error_html (itip, _("The message does not appear to be properly formed")); + g_object_unref (pitip->comp); + pitip->comp = NULL; + return; + }; + +// show_current (itip); +} + +static gboolean +format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) +{ + FormatItipPObject *pitip = (FormatItipPObject *) pobject; + ECalComponentText text; + ECalComponentOrganizer organizer; + ECalComponentDateTime datetime; + icaltimezone *from_zone, *to_zone; + const char *string; + + /* FIXME Error handling? */ + extract_itip_data (pitip); + + pitip->view = itip_view_new (); + gtk_widget_show (pitip->view); + + itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_REQUEST); + + e_cal_component_get_organizer (pitip->comp, &organizer); + itip_view_set_organizer (ITIP_VIEW (pitip->view), organizer.cn ? organizer.cn : itip_strip_mailto (organizer.value)); + /* FIXME, do i need to strip the sentby somehow? Maybe with camel? */ + itip_view_set_sentby (ITIP_VIEW (pitip->view), organizer.sentby); + + e_cal_component_get_summary (pitip->comp, &text); + itip_view_set_summary (ITIP_VIEW (pitip->view), text.value ? text.value : _("None")); + + e_cal_component_get_location (pitip->comp, &string); + itip_view_set_location (ITIP_VIEW (pitip->view), string); + + to_zone = calendar_config_get_icaltimezone (); + + e_cal_component_get_dtstart (pitip->comp, &datetime); + if (datetime.value) { + struct tm start_tm; + + /* FIXME Handle tzid that is not in the component - treat as "local" time */ + if (!datetime.value->is_utc && datetime.tzid) + from_zone = icalcomponent_get_timezone (pitip->top_level, datetime.tzid); + else + from_zone = NULL; + + start_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone); + + itip_view_set_start (ITIP_VIEW (pitip->view), &start_tm); + } + e_cal_component_free_datetime (&datetime); + + e_cal_component_get_dtend (pitip->comp, &datetime); + if (datetime.value) { + struct tm end_tm; + + /* FIXME Handle tzid that is not in the component - treat as "local" time */ + if (!datetime.value->is_utc && datetime.tzid) + from_zone = icalcomponent_get_timezone (pitip->top_level, datetime.tzid); + else + from_zone = NULL; + + end_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone); + + itip_view_set_end (ITIP_VIEW (pitip->view), &end_tm); + } + e_cal_component_free_datetime (&datetime); + + gtk_container_add (GTK_CONTAINER (eb), pitip->view); + + return TRUE; +} + +void +format_itip (EPlugin *ep, EMFormatHookTarget *target) +{ + FormatItipPObject *pitip; + + calendar_config_init (); + + pitip = (FormatItipPObject *) em_format_html_add_pobject ((EMFormatHTML *) target->format, sizeof (FormatItipPObject), CLASSID, target->part, format_itip_object); + // FIXME set the free function +// pitip->object.free = pitip_free; + camel_stream_printf (target->stream, "<table border=0 width=\"100%%\" cellpadding=3><tr>"); + camel_stream_printf (target->stream, "<td valign=top><object classid=\"%s\"></object></td><td width=100%% valign=top>", CLASSID); + camel_stream_printf (target->stream, "</td></tr></table>"); +} diff --git a/plugins/itip-formatter/itip-view.c b/plugins/itip-formatter/itip-view.c new file mode 100644 index 0000000000..e58506605b --- /dev/null +++ b/plugins/itip-formatter/itip-view.c @@ -0,0 +1,720 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: JP Rosevear <jpr@novell.com> + * + * Copyright 2004 Novell, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + +#include <string.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <libgnome/gnome-i18n.h> +#include <gconf/gconf-client.h> +#include <camel/camel-stream.h> +#include <camel/camel-stream-mem.h> +#include <camel/camel-medium.h> +#include <camel/camel-mime-message.h> +#include <libecal/e-cal.h> +#include <gtkhtml/gtkhtml-embedded.h> +#include <mail/em-format-hook.h> +#include <mail/em-format-html.h> +#include <e-util/e-account-list.h> +#include <e-util/e-icon-factory.h> +#include <e-util/e-time-utils.h> +#include <calendar/gui/itip-utils.h> +#include "itip-view.h" + +#define MEETING_ICON "stock_new-meeting" + +G_DEFINE_TYPE (ItipView, itip_view, GTK_TYPE_HBOX); + +struct _ItipViewPrivate { + ItipViewMode mode; + + GtkWidget *sender_label; + char *organizer; + char *sentby; + char *delegator; + char *attendee; + + GtkWidget *summary_label; + char *summary; + + GtkWidget *location_header; + GtkWidget *location_label; + char *location; + + GtkWidget *start_header; + GtkWidget *start_label; + struct tm *start_tm; + + GtkWidget *end_header; + GtkWidget *end_label; + struct tm *end_tm; +}; + +static void +format_date_and_time_x (struct tm *date_tm, + struct tm *current_tm, + gboolean use_24_hour_format, + gboolean show_midnight, + gboolean show_zero_seconds, + char *buffer, + int buffer_size) +{ + char *format; + + /* Today */ + if (date_tm->tm_mday == current_tm->tm_mday && + date_tm->tm_mon == current_tm->tm_mon && + date_tm->tm_year == current_tm->tm_year) { + if (!show_midnight && date_tm->tm_hour == 0 + && date_tm->tm_min == 0 && date_tm->tm_sec == 0) { + /* strftime format of a weekday and a date. */ + format = _("Today"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 24-hour format, without seconds. */ + format = _("Today %H:%M"); + else + /* strftime format of a weekday, a date and a + time, in 24-hour format. */ + format = _("Today %H:%M:%S"); + } else { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 12-hour format, without seconds. */ + format = _("Today %I:%M %p"); + else + /* strftime format of a weekday, a date and a + time, in 12-hour format. */ + format = _("Today %I:%M:%S %p"); + } + + /* Tomorrow */ + } else if (date_tm->tm_year == current_tm->tm_year) { + if (!show_midnight && date_tm->tm_hour == 0 + && date_tm->tm_min == 0 && date_tm->tm_sec == 0) { + /* strftime format of a weekday and a date. */ + format = _("%A, %B %e"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 24-hour format, without seconds. */ + format = _("%A, %B %e %H:%M"); + else + /* strftime format of a weekday, a date and a + time, in 24-hour format. */ + format = _("%A, %B %e %H:%M:%S"); + } else { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 12-hour format, without seconds. */ + format = _("%A, %B %e %I:%M %p"); + else + /* strftime format of a weekday, a date and a + time, in 12-hour format. */ + format = _("%A, %B %e %I:%M:%S %p"); + } + + /* Within 7 days */ + } else if (date_tm->tm_year == current_tm->tm_year) { + if (!show_midnight && date_tm->tm_hour == 0 + && date_tm->tm_min == 0 && date_tm->tm_sec == 0) { + /* strftime format of a weekday and a date. */ + format = _("%A"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 24-hour format, without seconds. */ + format = _("%A %H:%M"); + else + /* strftime format of a weekday, a date and a + time, in 24-hour format. */ + format = _("%A %H:%M:%S"); + } else { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 12-hour format, without seconds. */ + format = _("%A %I:%M %p"); + else + /* strftime format of a weekday, a date and a + time, in 12-hour format. */ + format = _("%A %I:%M:%S %p"); + } + + /* This Year */ + } else if (date_tm->tm_year == current_tm->tm_year) { + if (!show_midnight && date_tm->tm_hour == 0 + && date_tm->tm_min == 0 && date_tm->tm_sec == 0) { + /* strftime format of a weekday and a date. */ + format = _("%A, %B %e"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 24-hour format, without seconds. */ + format = _("%A, %B %e %H:%M"); + else + /* strftime format of a weekday, a date and a + time, in 24-hour format. */ + format = _("%A, %B %e %H:%M:%S"); + } else { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 12-hour format, without seconds. */ + format = _("%A, %B %e %I:%M %p"); + else + /* strftime format of a weekday, a date and a + time, in 12-hour format. */ + format = _("%A, %B %e %I:%M:%S %p"); + } + } else { + if (!show_midnight && date_tm->tm_hour == 0 + && date_tm->tm_min == 0 && date_tm->tm_sec == 0) { + /* strftime format of a weekday and a date. */ + format = _("%A, %B %e, %Y"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 24-hour format, without seconds. */ + format = _("%A, %B %e, %Y %H:%M"); + else + /* strftime format of a weekday, a date and a + time, in 24-hour format. */ + format = _("%A, %B %e, %Y %H:%M:%S"); + } else { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday, a date and a + time, in 12-hour format, without seconds. */ + format = _("%A, %B %e, %Y %I:%M %p"); + else + /* strftime format of a weekday, a date and a + time, in 12-hour format. */ + format = _("%A, %B %e, %Y %I:%M:%S %p"); + } + } + + /* strftime returns 0 if the string doesn't fit, and leaves the buffer + undefined, so we set it to the empty string in that case. */ + if (e_utf8_strftime (buffer, buffer_size, format, date_tm) == 0) + buffer[0] = '\0'; +} + +static void +set_sender_text (ItipView *view) +{ + ItipViewPrivate *priv; + const char *organizer, *attendee; + char *sender = NULL; + + priv = view->priv; + + organizer = priv->organizer ? priv->organizer : _("An unknown person"); + attendee = priv->attendee ? priv->attendee : _("An unknown person"); + + switch (priv->mode) { + case ITIP_VIEW_MODE_PUBLISH: + if (priv->sentby) + sender = g_strdup_printf (_("<b>%s</b> through %s has published meeting information."), organizer, priv->sentby); + else + sender = g_strdup_printf (_("<b>%s</b> has published meeting information."), organizer); + break; + case ITIP_VIEW_MODE_REQUEST: + /* FIXME is the delegator stuff handled correctly here? */ + if (priv->delegator) { + sender = g_strdup_printf (_("<b>%s</b> requests the presence of %s at a meeting."), organizer, priv->delegator); + } else { + if (priv->sentby) + sender = g_strdup_printf (_("<b>%s</b> through %s requests your presence at a meeting."), organizer, priv->sentby); + else + sender = g_strdup_printf (_("<b>%s</b> requests your presence at a meeting."), organizer); + } + break; + case ITIP_VIEW_MODE_ADD: + if (priv->sentby) + sender = g_strdup_printf (_("<b>%s</b> through %s wishes to add to an existing meeting."), organizer, priv->sentby); + else + sender = g_strdup_printf (_("<b>%s</b> wishes to add to an existing meeting."), organizer); + break; + case ITIP_VIEW_MODE_REFRESH: + sender = g_strdup_printf (_("<b>%s</b> wishes to receive the latest meeting information."), attendee); + break; + case ITIP_VIEW_MODE_REPLY: + sender = g_strdup_printf (_("<b>%s</b> has replied to a meeting invitation."), attendee); + break; + case ITIP_VIEW_MODE_CANCEL: + if (priv->sentby) + sender = g_strdup_printf (_("<b>%s</b> through %s has cancelled a meeting."), organizer, priv->sentby); + else + sender = g_strdup_printf (_("<b>%s</b> has cancelled a meeting."), organizer); + break; + default: + break; + } + + gtk_label_set_text (GTK_LABEL (priv->sender_label), sender); + gtk_label_set_use_markup (GTK_LABEL (priv->sender_label), TRUE); + + g_free (sender); +} + +static void +set_summary_text (ItipView *view) +{ + ItipViewPrivate *priv; + char *summary = NULL; + + priv = view->priv; + + summary = g_strdup_printf ("<b>%s</b>", priv->summary); + + gtk_label_set_text (GTK_LABEL (priv->summary_label), summary); + gtk_label_set_use_markup (GTK_LABEL (priv->summary_label), TRUE); + + g_free (summary); +} + +static void +set_location_text (ItipView *view) +{ + ItipViewPrivate *priv; + + priv = view->priv; + + gtk_label_set_text (GTK_LABEL (priv->location_label), priv->location); + + priv->location ? gtk_widget_show (priv->location_header) : gtk_widget_hide (priv->location_header); + priv->location ? gtk_widget_show (priv->location_label) : gtk_widget_hide (priv->location_label); +} + +static void +set_start_text (ItipView *view) +{ + ItipViewPrivate *priv; + char buffer[256]; + time_t now; + struct tm *now_tm; + + priv = view->priv; + + now = time (NULL); + now_tm = localtime (&now); + + if (priv->start_tm) { + format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, buffer, 256); + gtk_label_set_text (GTK_LABEL (priv->start_label), buffer); + } else { + gtk_label_set_text (GTK_LABEL (priv->start_label), NULL); + } + + priv->start_tm ? gtk_widget_show (priv->start_header) : gtk_widget_hide (priv->start_header); + priv->start_tm ? gtk_widget_show (priv->start_label) : gtk_widget_hide (priv->start_label); +} + +static void +set_end_text (ItipView *view) +{ + ItipViewPrivate *priv; + char buffer[256]; + time_t now; + struct tm *now_tm; + + priv = view->priv; + + now = time (NULL); + now_tm = localtime (&now); + + if (priv->end_tm) { + format_date_and_time_x (priv->end_tm, now_tm, FALSE, TRUE, FALSE, buffer, 256); + gtk_label_set_text (GTK_LABEL (priv->end_label), buffer); + } else { + gtk_label_set_text (GTK_LABEL (priv->end_label), NULL); + } + + priv->end_tm ? gtk_widget_show (priv->end_header) : gtk_widget_hide (priv->end_header); + priv->end_tm ? gtk_widget_show (priv->end_label) : gtk_widget_hide (priv->end_label); +} + +static void +itip_view_destroy (GtkObject *object) +{ + ItipView *view = ITIP_VIEW (object); + ItipViewPrivate *priv = view->priv; + + if (priv) { + g_free (priv->organizer); + g_free (priv->sentby); + g_free (priv->delegator); + g_free (priv->attendee); + g_free (priv->location); + g_free (priv->start_tm); + g_free (priv->end_tm); + + g_free (priv); + view->priv = NULL; + } + + GTK_OBJECT_CLASS (itip_view_parent_class)->destroy (object); +} + +static void +itip_view_class_init (ItipViewClass *klass) +{ + GObjectClass *object_class; + GtkObjectClass *gtkobject_class; + + object_class = G_OBJECT_CLASS (klass); + gtkobject_class = GTK_OBJECT_CLASS (klass); + + gtkobject_class->destroy = itip_view_destroy; +} + +static void +itip_view_init (ItipView *view) +{ + ItipViewPrivate *priv; + GtkWidget *icon, *vbox, *separator, *table; + + priv = g_new0 (ItipViewPrivate, 1); + view->priv = priv; + + priv->mode = ITIP_VIEW_MODE_NONE; + + /* The icon on the LHS */ + icon = e_icon_factory_get_image (MEETING_ICON, E_ICON_SIZE_LARGE_TOOLBAR); + gtk_misc_set_alignment (GTK_MISC (icon), 0, 0); + gtk_widget_show (icon); + + gtk_box_pack_start (GTK_BOX (view), icon, FALSE, FALSE, 6); + + /* The RHS */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (view), vbox, FALSE, FALSE, 6); + + /* The first section listing the sender */ + /* FIXME What to do if the send and organizer do not match */ + priv->sender_label = gtk_label_new (NULL); + gtk_widget_show (priv->sender_label); + gtk_box_pack_start (GTK_BOX (vbox), priv->sender_label, FALSE, FALSE, 6); + + separator = gtk_hseparator_new (); + gtk_widget_show (separator); + gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 6); + + /* A table with information on the meeting and any extra info/warnings */ + table = gtk_table_new (3, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 6); + + /* Summary */ + priv->summary_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->summary_label), 0, 0.5); + gtk_widget_show (priv->summary_label); + gtk_table_attach (GTK_TABLE (table), priv->summary_label, 0, 2, 0, 1, GTK_FILL, 0, 0, 0); + + /* Location */ + priv->location_header = gtk_label_new (_("Location:")); + priv->location_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->location_label), 0, 0.5); + gtk_table_attach (GTK_TABLE (table), priv->location_header, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); + gtk_table_attach (GTK_TABLE (table), priv->location_label, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); + + priv->start_header = gtk_label_new (_("Starts:")); + priv->start_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->start_header), 0, 0.5); + gtk_misc_set_alignment (GTK_MISC (priv->start_label), 0, 0.5); + gtk_widget_show (priv->start_header); + gtk_table_attach (GTK_TABLE (table), priv->start_header, 0, 1, 2, 3, GTK_FILL, 0, 0, 0); + gtk_table_attach (GTK_TABLE (table), priv->start_label, 1, 2, 2, 3, GTK_FILL, 0, 0, 0); + + priv->end_header = gtk_label_new (_("Ends:")); + priv->end_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->end_header), 0, 0.5); + gtk_misc_set_alignment (GTK_MISC (priv->end_label), 0, 0.5); + gtk_table_attach (GTK_TABLE (table), priv->end_header, 0, 1, 3, 4, GTK_FILL, 0, 0, 0); + gtk_table_attach (GTK_TABLE (table), priv->end_label, 1, 2, 3, 4, GTK_FILL, 0, 0, 0); + + /* The buttons for actions */ +} + +GtkWidget * +itip_view_new (void) +{ + ItipView *itip_view = g_object_new (ITIP_TYPE_VIEW, "homogeneous", FALSE, "spacing", 6, NULL); + + return GTK_WIDGET (itip_view); +} + +void +itip_view_set_mode (ItipView *view, ItipViewMode mode) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + priv->mode = mode; + + set_sender_text (view); +} + +ItipViewMode +itip_view_get_mode (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, ITIP_VIEW_MODE_NONE); + g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE); + + priv = view->priv; + + return priv->mode; +} + +void +itip_view_set_organizer (ItipView *view, const char *organizer) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->organizer) + g_free (priv->organizer); + + priv->organizer = g_strdup (organizer); + + set_sender_text (view); +} + +const char * +itip_view_get_organizer (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->organizer; +} + +void +itip_view_set_sentby (ItipView *view, const char *sentby) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->sentby) + g_free (priv->sentby); + + priv->sentby = g_strdup (sentby); + + set_sender_text (view); +} + +const char * +itip_view_get_sentby (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->sentby; +} + +void +itip_view_set_attendee (ItipView *view, const char *attendee) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->attendee) + g_free (priv->attendee); + + priv->attendee = g_strdup (attendee); + + set_sender_text (view); +} + +const char * +itip_view_get_attendee (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->attendee; +} + +void +itip_view_set_summary (ItipView *view, const char *summary) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->summary) + g_free (priv->summary); + + priv->summary = g_strdup (summary); + + set_summary_text (view); +} + +const char * +itip_view_get_summary (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->summary; +} + +void +itip_view_set_location (ItipView *view, const char *location) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->location) + g_free (priv->location); + + priv->location = g_strdup (location); + + set_location_text (view); +} + +const char * +itip_view_get_location (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->location; +} + +void +itip_view_set_start (ItipView *view, struct tm *start) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->start_tm && !start) { + g_free (priv->start_tm); + priv->start_tm = NULL; + } else if (start) { + if (!priv->start_tm) + priv->start_tm = g_new0 (struct tm, 1); + + *priv->start_tm = *start; + } + + set_start_text (view); +} + +const struct tm * +itip_view_get_start (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->start_tm; +} + +void +itip_view_set_end (ItipView *view, struct tm *end) +{ + ItipViewPrivate *priv; + + g_return_if_fail (view != NULL); + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + if (priv->end_tm && !end) { + g_free (priv->end_tm); + priv->end_tm = NULL; + } else if (end) { + if (!priv->end_tm) + priv->end_tm = g_new0 (struct tm, 1); + + *priv->end_tm = *end; + } + + set_end_text (view); +} + +const struct tm * +itip_view_get_end (ItipView *view) +{ + ItipViewPrivate *priv; + + g_return_val_if_fail (view != NULL, NULL); + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + priv = view->priv; + + return priv->end_tm; +} diff --git a/plugins/itip-formatter/itip-view.h b/plugins/itip-formatter/itip-view.h new file mode 100644 index 0000000000..ac9305bf2e --- /dev/null +++ b/plugins/itip-formatter/itip-view.h @@ -0,0 +1,102 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* itip-view.h + * + * Copyright (C) 2004 Novell, 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. + * + * Author: JP Rosevear + */ + +#ifndef _ITIP_VIEW_H_ +#define _ITIP_VIEW_H_ + +#include <glib-object.h> +#include <gtk/gtkhbox.h> + +G_BEGIN_DECLS + +#define ITIP_TYPE_VIEW (itip_view_get_type ()) +#define ITIP_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), ITIP_TYPE_VIEW, ItipView)) +#define ITIP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ITIP_TYPE_VIEW, ItipViewClass)) +#define ITIP_IS_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), ITIP_TYPE_VIEW)) +#define ITIP_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ITIP_TYPE_VIEW)) +#define ITIP_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ITIP_TYPE_VIEW, ItipViewClass)) + +typedef struct _ItipView ItipView; +typedef struct _ItipViewPrivate ItipViewPrivate; +typedef struct _ItipViewClass ItipViewClass; + +typedef enum { + ITIP_VIEW_MODE_NONE, + ITIP_VIEW_MODE_PUBLISH, + ITIP_VIEW_MODE_REQUEST, + ITIP_VIEW_MODE_ADD, + ITIP_VIEW_MODE_REPLY, + ITIP_VIEW_MODE_REFRESH, + ITIP_VIEW_MODE_CANCEL +} ItipViewMode; + +typedef enum { + ITIP_VIEW_RESPONSE_NONE, + ITIP_VIEW_RESPONSE_ACCEPT, + ITIP_VIEW_RESPONSE_TENTATIVE, + ITIP_VIEW_RESPONSE_DECLINE, + ITIP_VIEW_RESPONSE_UPDATE, + ITIP_VIEW_RESPONSE_SEND +} ItipViewResponse; + +struct _ItipView +{ + GtkHBox parent_instance; + + ItipViewPrivate *priv; +}; + +struct _ItipViewClass +{ + GtkHBoxClass parent_class; +}; + +GType itip_view_get_type (void); +GtkWidget *itip_view_new (void); + +void itip_view_set_mode (ItipView *view, ItipViewMode mode); +ItipViewMode itip_view_get_mode (ItipView *view); + +void itip_view_set_organizer (ItipView *view, const char *organizer); +const char *itip_view_get_organizer (ItipView *view); + +void itip_view_set_sentby (ItipView *view, const char *sentby); +const char *itip_view_get_sentby (ItipView *view); + +void itip_view_set_attendee (ItipView *view, const char *attendee); +const char *itip_view_get_attendee (ItipView *view); + +void itip_view_set_summary (ItipView *view, const char *summary); +const char *itip_view_get_summary (ItipView *view); + +void itip_view_set_location (ItipView *view, const char *location); +const char *itip_view_get_location (ItipView *view); + +void itip_view_set_start (ItipView *view, struct tm *start); +const struct tm *itip_view_get_start (ItipView *view); + +void itip_view_set_end (ItipView *view, struct tm *end); +const struct tm *itip_view_get_end (ItipView *view); + +G_END_DECLS + +#endif diff --git a/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in b/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in new file mode 100644 index 0000000000..901e695bd0 --- /dev/null +++ b/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in @@ -0,0 +1,14 @@ +<e-plugin-list> + <e-plugin id="org.gnome.evolution.itip_formatter" type="shlib" name="Itip Formatter" description="Displays text/calendar parts in messages" + location="@PLUGINDIR@/liborg-gnome-itip-formatter.so"> + + <hook class="org.gnome.evolution.mail.format:1.0"> + <group id="EMFormatHTMLDisplay"> + <item mime_type="text/calendar" flags="inline_disposition" format="format_itip"/> + </group> + <group id="EMFormat"> + <item mime_type="text/calendar" flags="inline_disposition" format="format_itip"/> + </group> + </hook> + </e-plugin> +</e-plugin-list>
\ No newline at end of file |