/* Evolution calendar - Meeting editor dialog
*
* Copyright (C) 2000 Helix Code, Inc.
* Copyright (C) 2000 Ximian, Inc.
*
* Authors: Jesse Pavel <jpavel@ximian.com>
*
* 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 Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <gtk/gtkclist.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkmain.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkwindow.h>
#include <gdk_imlib.h>
#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-dialog-util.h>
#include <bonobo/bonobo-object.h>
#include <bonobo/bonobo-object-client.h>
#include <glade/glade.h>
#include <ical.h>
#include <widgets/meeting-time-sel/e-meeting-time-sel.h>
#include <Evolution-Composer.h>
#include <string.h>
#include "e-meeting-edit.h"
#include "itip-utils.h"
#define E_MEETING_GLADE_XML "e-meeting-dialog.glade"
typedef struct _EMeetingEditorPrivate EMeetingEditorPrivate;
struct _EMeetingEditorPrivate {
/* These are the widgets to be used in the GUI. */
GladeXML *xml;
GtkWidget *meeting_window;
GtkWidget *attendee_list;
GtkWidget *address_entry;
GtkWidget *edit_dialog;
GtkWidget *organizer_entry;
GtkWidget *role_entry;
GtkWidget *rsvp_check;
GtkWidget *publish_button, *request_button, *cancel_button,
*schedule_button;
gint changed_signal_id;
/* Various pieces of information. */
gint selected_row;
CalComponent *comp;
CalClient *client;
icalcomponent *icalcomp, *vevent;
gint numentries; /* How many attendees are there? */
gboolean dirty; /* Has anything changed? */
};
#define NUM_COLUMNS 4 /* The number of columns in our attendee list. */
enum column_names {ADDRESS_COL, ROLE_COL, RSVP_COL, STATUS_COL};
static void
save_organizer (EMeetingEditorPrivate *priv)
{
icalproperty *prop;
icalvalue *value;
gchar *text;
/* Save the organizer into the iCAL object. */
text = gtk_entry_get_text (GTK_ENTRY (priv->organizer_entry));
if (strlen (text) > 0) {
gchar buffer[200];
g_snprintf (buffer, 190, "MAILTO:%s", text);
prop = icalcomponent_get_first_property (priv->vevent, ICAL_ORGANIZER_PROPERTY);
if (prop == NULL) {
/* We need to add an ORGANIZER property. */
prop = icalproperty_new (ICAL_ORGANIZER_PROPERTY);
icalcomponent_add_property (priv->vevent, prop);
}
value = icalvalue_new_text (buffer);
icalproperty_set_value (prop, value);
}
}
static gboolean
window_delete_cb (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
save_organizer (priv);
if (priv->dirty == TRUE) {
/* FIXME: notify the event editor that our data has changed.
For now, I'll just display a dialog box. */
{
if (!cal_client_update_object (priv->client, priv->comp)) {
GtkWidget *dialog;
dialog = gnome_warning_dialog_parented ("I couldn't automatically save this meeting,\n"
"so try to save this event manually.",
GTK_WINDOW (priv->meeting_window));
gnome_dialog_run (GNOME_DIALOG(dialog));
}
}
}
gtk_entry_set_text (GTK_ENTRY (priv->organizer_entry), "");
return (FALSE);
}
static void
window_destroy_cb (GtkWidget *widget,
gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
gtk_main_quit ();
return;
}
/* put_property_in_list() synchronizes the display of row `rownum'
in our attendee list to the values of `prop'. If rownum < 0,
then put_property_in_list() will append a new row.
If the property doesn't contain certain parameters that we deem
necessary, it will add them. */
static void
put_property_in_list (icalproperty *prop, gint rownum, gpointer data)
{
gchar *row_text[NUM_COLUMNS];
gchar *text, *new_text;
icalparameter *param;
icalvalue *value;
gint enumval;
gint cntr;
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
value = icalproperty_get_value (prop);
if (value != NULL) {
text = strdup (icalvalue_as_ical_string (value));
/* Here I strip off the "MAILTO:" if it is present. */
new_text = strchr (text, ':');
if (new_text != NULL)
new_text++;
else
new_text = text;
row_text[ADDRESS_COL] = g_strdup (new_text);
g_free (text);
}
param = get_icalparam_by_type (prop, ICAL_ROLE_PARAMETER);
if (param == NULL) {
param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
icalproperty_add_parameter (prop, param);
}
enumval = icalparameter_get_role (param);
if (enumval < 0 || enumval > 4)
enumval = 4;
row_text[ROLE_COL] = role_values [enumval];
param = get_icalparam_by_type (prop, ICAL_RSVP_PARAMETER);
if (param == NULL) {
param = icalparameter_new_rsvp (TRUE);
icalproperty_add_parameter (prop, param);
}
if (icalparameter_get_rsvp (param))
row_text[RSVP_COL] = "Y";
else
row_text[RSVP_COL] = "N";
param = get_icalparam_by_type (prop, ICAL_PARTSTAT_PARAMETER);
if (param == NULL) {
param = icalparameter_new_partstat (ICAL_PARTSTAT_NEEDSACTION);
icalproperty_add_parameter (prop, param);
}
enumval = icalparameter_get_partstat (param);
if (enumval < 0 || enumval > 7) {
enumval = 7;
}
row_text[STATUS_COL] = partstat_values [enumval];
if (rownum < 0) {
gtk_clist_append (GTK_CLIST (priv->attendee_list), row_text);
gtk_clist_set_row_data (GTK_CLIST (priv->attendee_list), priv->numentries, prop);
priv->numentries++;
}
else {
for (cntr = 0; cntr < NUM_COLUMNS; cntr++) {
gtk_clist_set_text (GTK_CLIST (priv->attendee_list),
rownum,
cntr,
row_text[cntr]);
}
}
g_free (row_text[ADDRESS_COL]);
}
/********
* edit_attendee() performs the GUI manipulation and interaction for
* editing `prop' and returns TRUE if the user indicated that he wants
* to save the new property information.
*
* Note that it is necessary that the property have parameters of the types
* RSVP, PARTSTAT, and ROLE already when passed into this function.
********/
static gboolean
edit_attendee (icalproperty *prop, gpointer data)
{
EMeetingEditorPrivate *priv;
gint button_num;
gchar *new_text, *text;
icalparameter *param;
icalvalue *value;
gchar buffer[200];
gint cntr;
gint enumval;
gboolean retval;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
g_return_val_if_fail (prop != NULL, FALSE);
if (priv->edit_dialog == NULL || priv->address_entry == NULL) {
priv->edit_dialog = glade_xml_get_widget (priv->xml, "edit_dialog");
priv->address_entry = glade_xml_get_widget (priv->xml, "address_entry");
gnome_dialog_set_close (GNOME_DIALOG (priv->edit_dialog), TRUE);
gnome_dialog_editable_enters (GNOME_DIALOG (priv->edit_dialog),
GTK_EDITABLE (priv->address_entry));
gnome_dialog_close_hides (GNOME_DIALOG (priv->edit_dialog), TRUE);
gnome_dialog_set_default (GNOME_DIALOG (priv->edit_dialog), 0);
}
g_return_val_if_fail (priv->edit_dialog != NULL, FALSE);
g_return_val_if_fail (priv->address_entry != NULL, FALSE);
gtk_widget_realize (priv->edit_dialog);
value = icalproperty_get_value (prop);
if (value != NULL) {
text = strdup (icalvalue_as_ical_string (value));
/* Here I strip off the "MAILTO:" if it is present. */
new_text = strchr (text, ':');
if (new_text != NULL)
new_text++;
else
new_text = text;
gtk_entry_set_text (GTK_ENTRY (priv->address_entry), new_text);
g_free (text);
}
else {
gtk_entry_set_text (GTK_ENTRY (priv->address_entry), "");
}
param = get_icalparam_by_type (prop, ICAL_ROLE_PARAMETER);
enumval = icalparameter_get_role (param);
if (enumval < 0 || enumval > 4)
enumval = 4;
text = role_values [enumval];
gtk_entry_set_text (GTK_ENTRY (priv->role_entry), text);
param = get_icalparam_by_type (prop, ICAL_RSVP_PARAMETER);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rsvp_check),
icalparameter_get_rsvp (param));
gtk_widget_show (priv->edit_dialog);
button_num = gnome_dialog_run (GNOME_DIALOG (priv->edit_dialog));
if (button_num == 0) {
/* The user pressed the OK button. */
new_text = gtk_entry_get_text (GTK_ENTRY (priv->address_entry));
g_snprintf (buffer, 190, "MAILTO:%s", new_text);
value = icalvalue_new_text (buffer);
icalproperty_set_value (prop, value);
/* Take care of the ROLE. */
icalproperty_remove_parameter (prop, ICAL_ROLE_PARAMETER);
param = NULL;
text = gtk_entry_get_text (GTK_ENTRY(priv->role_entry));
for (cntr = 0; cntr < 5; cntr++) {
if (strncmp (text, role_values[cntr], 3) == 0) {
param = icalparameter_new_role (cntr);
break;
}
}
if (param == NULL) {
g_print ("e-meeting-edit.c: edit_attendee() the ROLE param was null.\n");
/* Use this as a default case, if none of the others match. */
param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
}
icalproperty_add_parameter (prop, param);
/* Now the RSVP. */
icalproperty_remove_parameter (prop, ICAL_RSVP_PARAMETER);
param = icalparameter_new_rsvp
(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rsvp_check)));
icalproperty_add_parameter (prop, param);
retval = TRUE;
}
else /* The user didn't say OK. */
retval = FALSE;
return retval;
}
static void
schedule_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
EMeetingTimeSelector *mts;
EMeetingTimeSelectorAttendeeType type;
GtkWidget *dialog;
gchar *attendee;
gint cntr, row;
icalproperty *prop;
icalparameter *param;
gint button_num;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
gtk_widget_push_visual (gdk_imlib_get_visual ());
gtk_widget_push_colormap (gdk_imlib_get_colormap ());
dialog = gnome_dialog_new ("Schedule Meeting", "Set Time", "Cancel", NULL);
gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 400);
gtk_window_set_policy (GTK_WINDOW (dialog), FALSE, TRUE, FALSE);
mts = (EMeetingTimeSelector *)e_meeting_time_selector_new ();
gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), GTK_WIDGET (mts));
gtk_window_add_accel_group (GTK_WINDOW (dialog),
E_MEETING_TIME_SELECTOR (mts)->accel_group);
gtk_widget_show (GTK_WIDGET (mts));
gtk_widget_pop_visual ();
gtk_widget_pop_colormap ();
/* Let's stick all the attendees that we have in our clist, into the
meeting time widget. */
for (cntr = 0; cntr < priv->numentries; cntr++ ) {
gtk_clist_get_text (GTK_CLIST (priv->attendee_list), cntr,
ADDRESS_COL, &attendee);
row = e_meeting_time_selector_attendee_add (mts, attendee, NULL);
prop = (icalproperty *)gtk_clist_get_row_data (GTK_CLIST (priv->attendee_list), cntr);
param = get_icalparam_by_type (prop, ICAL_ROLE_PARAMETER);
switch (icalparameter_get_role (param)) {
case ICAL_ROLE_CHAIR:
case ICAL_ROLE_REQPARTICIPANT:
type = E_MEETING_TIME_SELECTOR_REQUIRED_PERSON;
break;
default:
type = E_MEETING_TIME_SELECTOR_OPTIONAL_PERSON;
}
e_meeting_time_selector_attendee_set_type (mts, row, type);
}
/* I don't want the meeting widget to be destroyed before I can
extract information from it; so now the dialog window will just
be hidden when the user clicks a button or closes it. */
gnome_dialog_close_hides (GNOME_DIALOG (dialog), TRUE);
gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE);
button_num = gnome_dialog_run (GNOME_DIALOG (dialog));
if (button_num == 0) {
/* The user clicked "Set Time". */
gint start_year, start_month, start_day, start_hour, start_minute,
end_year, end_month, end_day, end_hour, end_minute;
CalComponentDateTime cal_dtstart, cal_dtend;
e_meeting_time_selector_get_meeting_time (mts,
&start_year,
&start_month,
&start_day,
&start_hour,
&start_minute,
&end_year,
&end_month,
&end_day,
&end_hour,
&end_minute);
cal_component_get_dtstart (priv->comp, &cal_dtstart);
cal_component_get_dtend (priv->comp, &cal_dtend);
cal_dtstart.value->second = 0;
cal_dtstart.value->minute = start_minute;
cal_dtstart.value->hour = start_hour;
cal_dtstart.value->day = start_day;
cal_dtstart.value->month = start_month;
cal_dtstart.value->year = start_year;
cal_dtend.value->second = 0;
cal_dtend.value->minute = end_minute;
cal_dtend.value->hour = end_hour;
cal_dtend.value->day = end_day;
cal_dtend.value->month = end_month;
cal_dtend.value->year = end_year;
cal_component_set_dtstart (priv->comp, &cal_dtstart);
cal_component_set_dtend (priv->comp, &cal_dtend);
cal_component_free_datetime (&cal_dtstart);
cal_component_free_datetime (&cal_dtend);
priv->dirty = TRUE;
}
gtk_widget_destroy (GTK_WIDGET (dialog));
return;
}
#define GNOME_EVOLUTION_COMPOSER_OAFIID "OAFIID:GNOME_Evolution_Mail_Composer"
static gchar *itip_methods[] = {
"REQUEST",
"PUBLISH",
"CANCEL"
};
enum itip_method_enum {
METHOD_REQUEST,
METHOD_PUBLISH,
METHOD_CANCEL
};
typedef enum itip_method_enum itip_method_enum;
static void
send_calendar_info (itip_method_enum method, EMeetingEditorPrivate *priv)
{
BonoboObjectClient *bonobo_server;
GNOME_Evolution_Composer composer_server;
CORBA_Environment ev;
GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list;
GNOME_Evolution_Composer_Recipient *recipient;
gchar *cell_text;
CORBA_char *subject;
gint cntr;
gint len;
CalComponentText caltext;
CORBA_char *content_type, *filename, *description, *attach_data;
CORBA_boolean show_inline;
CORBA_char tempstr[200];
CORBA_exception_init (&ev);
/* First, I obtain an object reference that represents the Composer. */
bonobo_server = bonobo_object_activate (GNOME_EVOLUTION_COMPOSER_OAFIID, 0);
g_return_if_fail (bonobo_server != NULL);
composer_server = bonobo_object_corba_objref (BONOBO_OBJECT (bonobo_server));
/* All right, now I have to convert my list of recipients into one of those
CORBA sequences. */
to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
to_list->_maximum = priv->numentries;
to_list->_length = priv->numentries;
to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (priv->numentries);
for (cntr = 0; cntr < priv->numentries; cntr++) {
gtk_clist_get_text (GTK_CLIST (priv->attendee_list),
cntr, ADDRESS_COL,
&cell_text);
len = strlen (cell_text);
recipient = &(to_list->_buffer[cntr]);
recipient->name = CORBA_string_alloc (0); /* FIXME: we may want an actual name here. */
recipient->name[0] = '\0';
recipient->address = CORBA_string_alloc (len);
strcpy (recipient->address, cell_text);
}
cc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
cc_list->_maximum = cc_list->_length = 0;
bcc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
bcc_list->_maximum = bcc_list->_length = 0;
cal_component_get_summary (priv->comp, &caltext);
subject = CORBA_string_alloc (strlen (caltext.value));
strcpy (subject, caltext.value);
GNOME_Evolution_Composer_setHeaders (composer_server, to_list, cc_list, bcc_list, subject, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_printerr ("gui/e-meeting-edit.c: I couldn't set the composer headers via CORBA! Aagh.\n");
CORBA_exception_free (&ev);
return;
}
sprintf (tempstr, "text/calendar;METHOD=%s", itip_methods[method]);
content_type = CORBA_string_alloc (strlen (tempstr));
strcpy (content_type, tempstr);
filename = CORBA_string_alloc (0);
filename[0] = '\0';
sprintf (tempstr, "Calendar attachment");
description = CORBA_string_alloc (strlen (tempstr));
strcpy (description, tempstr);
show_inline = FALSE;
/* I need to create an encapsulating iCalendar component, and stuff our vEvent
into it. */
{
icalcomponent *comp;
icalproperty *prop;
icalvalue *value;
gchar *ical_string;
save_organizer (priv);
comp = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
prop = icalproperty_new (ICAL_PRODID_PROPERTY);
value = icalvalue_new_text ("-//HelixCode/Evolution//EN");
icalproperty_set_value (prop, value);
icalcomponent_add_property (comp, prop);
prop = icalproperty_new (ICAL_VERSION_PROPERTY);
value = icalvalue_new_text ("2.0");
icalproperty_set_value (prop, value);
icalcomponent_add_property (comp, prop);
prop = icalproperty_new (ICAL_METHOD_PROPERTY);
value = icalvalue_new_text (itip_methods[method]);
icalproperty_set_value (prop, value);
icalcomponent_add_property (comp, prop);
icalcomponent_add_component (comp, priv->vevent);
ical_string = icalcomponent_as_ical_string (comp);
attach_data = CORBA_string_alloc (strlen (ical_string));
strcpy (attach_data, ical_string);
icalcomponent_remove_component (comp, priv->vevent);
icalcomponent_free (comp);
}
GNOME_Evolution_Composer_attachData (composer_server,
content_type, filename, description,
show_inline, attach_data,
&ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_printerr ("gui/e-meeting-edit.c: I couldn't attach data to the composer via CORBA! Aagh.\n");
CORBA_exception_free (&ev);
return;
}
GNOME_Evolution_Composer_show (composer_server, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_printerr ("gui/e-meeting-edit.c: I couldn't show the composer via CORBA! Aagh.\n");
CORBA_exception_free (&ev);
return;
}
CORBA_exception_free (&ev);
/* Let's free shit up. */
/* Beware--depending on whether CORBA_free is recursive, which I
think is is, we might have memory leaks, in which case the code
below is necessary. */
#if 0
for (cntr = 0; cntr < priv->numentries; cntr++) {
recipient = &(to_list->_buffer[cntr]);
CORBA_free (recipient->name);
CORBA_free (recipient->address);
recipient->name = recipient->address = NULL;
}
#endif
if (CORBA_sequence_get_release (to_list) != FALSE)
CORBA_free (to_list->_buffer);
CORBA_free (to_list);
CORBA_free (cc_list);
CORBA_free (bcc_list);
CORBA_free (subject);
CORBA_free (content_type);
CORBA_free (filename);
CORBA_free (description);
CORBA_free (attach_data);
/* bonobo_object_unref (BONOBO_OBJECT (bonobo_server)); */
}
/********
* This routine is called when the publish button is clicked. Duh.
* Actually, I'm just testing my commenting macros.
********/
static void
publish_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
send_calendar_info (METHOD_PUBLISH, priv);
}
static void
request_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
send_calendar_info (METHOD_REQUEST, priv);
}
static void
cancel_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
send_calendar_info (METHOD_CANCEL, priv);
}
static void
add_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
icalproperty *prop;
icalparameter *param;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
prop = icalproperty_new (ICAL_ATTENDEE_PROPERTY);
param = icalparameter_new_role (ICAL_ROLE_REQPARTICIPANT);
icalproperty_add_parameter (prop, param);
param = icalparameter_new_rsvp (ICAL_RSVP_TRUE);
icalproperty_add_parameter (prop, param);
param = icalparameter_new_partstat (ICAL_PARTSTAT_NEEDSACTION);
icalproperty_add_parameter (prop, param);
if (edit_attendee (prop, data) == TRUE) {
/* Let's add this property to our component and to the CList. */
icalcomponent_add_property (priv->vevent, prop);
/* The -1 indicates that we should add a new row. */
put_property_in_list (prop, -1, data);
priv->dirty = TRUE;
}
else {
icalproperty_free (prop);
}
}
static void
delete_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
if (priv->selected_row < 0) {
GtkWidget *dialog;
dialog = gnome_warning_dialog_parented ("You must select an entry to delete.",
GTK_WINDOW (priv->meeting_window));
gnome_dialog_run (GNOME_DIALOG(dialog));
}
else {
/* Delete the associated property from the iCAL object. */
icalproperty *prop;
prop = (icalproperty *)gtk_clist_get_row_data (GTK_CLIST (priv->attendee_list),
priv->selected_row);
icalcomponent_remove_property (priv->vevent, prop);
icalproperty_free (prop);
gtk_clist_remove (GTK_CLIST (priv->attendee_list), priv->selected_row);
priv->selected_row = -1;
priv->numentries--;
priv->dirty = TRUE;
}
}
static void
edit_button_clicked_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
if (priv->selected_row < 0) {
GtkWidget *dialog;
dialog = gnome_warning_dialog_parented ("You must select an entry to edit.",
GTK_WINDOW (priv->meeting_window));
gnome_dialog_run (GNOME_DIALOG(dialog));
return;
}
else {
icalproperty *prop, *new_prop;
icalparameter *param;
icalvalue *value;
prop = (icalproperty *)gtk_clist_get_row_data (GTK_CLIST (priv->attendee_list),
priv->selected_row);
g_assert (prop != NULL);
new_prop = icalproperty_new_clone (prop);
if (edit_attendee (new_prop, data)) {
/* The user hit Okay. */
/*We need to synchronize the old property with the newly edited one.*/
value = icalvalue_new_clone (icalproperty_get_value (new_prop));
icalproperty_set_value (prop, value);
icalproperty_remove_parameter (prop, ICAL_ROLE_PARAMETER);
icalproperty_remove_parameter (prop, ICAL_RSVP_PARAMETER);
icalproperty_remove_parameter (prop, ICAL_PARTSTAT_PARAMETER);
param = icalparameter_new_clone (get_icalparam_by_type (new_prop, ICAL_ROLE_PARAMETER));
g_assert (param != NULL);
icalproperty_add_parameter (prop, param);
param = icalparameter_new_clone (get_icalparam_by_type (new_prop, ICAL_RSVP_PARAMETER));
g_assert (param != NULL);
icalproperty_add_parameter (prop, param);
param = icalparameter_new_clone (get_icalparam_by_type (new_prop, ICAL_PARTSTAT_PARAMETER));
g_assert (param != NULL);
icalproperty_add_parameter (prop, param);
put_property_in_list (prop, priv->selected_row, data);
priv->dirty = TRUE;
}
icalproperty_free (new_prop);
}
}
static void
list_row_select_cb (GtkWidget *widget,
gint row,
gint column,
GdkEventButton *event,
gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
priv->selected_row = row;
}
static void
organizer_changed_cb (GtkWidget *widget, gpointer data)
{
EMeetingEditorPrivate *priv;
priv = (EMeetingEditorPrivate *) ((EMeetingEditor *)data)->priv;
gtk_signal_disconnect (GTK_OBJECT (priv->organizer_entry), priv->changed_signal_id);
priv->dirty = TRUE;
}
/* ------------------------------------------------------------ */
/* --------------------- Exported Functions ------------------- */
/* ------------------------------------------------------------ */
EMeetingEditor *
e_meeting_editor_new (CalComponent *comp, CalClient *client)
{
EMeetingEditor *object;
EMeetingEditorPrivate *priv;
object = (EMeetingEditor *)g_new(EMeetingEditor, 1);
priv = (EMeetingEditorPrivate *) g_new0(EMeetingEditorPrivate, 1);
priv->selected_row = -1;
priv->comp = comp;
priv->client = client;
priv->icalcomp = cal_component_get_icalcomponent (comp);
object->priv = priv;
return object;
}
void
e_meeting_editor_free (EMeetingEditor *editor)
{
if (editor == NULL)
return;
if (editor->priv != NULL)
g_free (editor->priv);
g_free (editor);
}
void
e_meeting_edit (EMeetingEditor *editor)
{
EMeetingEditorPrivate *priv;
GtkWidget *add_button, *delete_button, *edit_button;
icalproperty *prop;
icalvalue *value;
gchar *text;
g_return_if_fail (editor != NULL);
priv = (EMeetingEditorPrivate *)editor->priv;
g_return_if_fail (priv != NULL);
priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/" E_MEETING_GLADE_XML, NULL);
priv->meeting_window = glade_xml_get_widget (priv->xml, "meeting_window");
priv->attendee_list = glade_xml_get_widget (priv->xml, "attendee_list");
priv->role_entry = glade_xml_get_widget (priv->xml, "role_entry");
priv->rsvp_check = glade_xml_get_widget (priv->xml, "rsvp_check");
priv->schedule_button = glade_xml_get_widget (priv->xml, "schedule_button");
priv->publish_button = glade_xml_get_widget (priv->xml, "publish_button");
priv->request_button = glade_xml_get_widget (priv->xml, "request_button");
priv->cancel_button = glade_xml_get_widget (priv->xml, "cancel_button");
gtk_clist_set_column_justification (GTK_CLIST (priv->attendee_list), ROLE_COL, GTK_JUSTIFY_CENTER);
gtk_clist_set_column_justification (GTK_CLIST (priv->attendee_list), RSVP_COL, GTK_JUSTIFY_CENTER);
gtk_clist_set_column_justification (GTK_CLIST (priv->attendee_list), STATUS_COL, GTK_JUSTIFY_CENTER);
gtk_signal_connect (GTK_OBJECT (priv->meeting_window), "delete_event",
GTK_SIGNAL_FUNC (window_delete_cb), editor);
gtk_signal_connect_after (GTK_OBJECT (priv->meeting_window), "delete_event",
GTK_SIGNAL_FUNC (window_destroy_cb), editor);
gtk_signal_connect (GTK_OBJECT (priv->meeting_window), "destroy_event",
GTK_SIGNAL_FUNC (window_destroy_cb), editor);
gtk_signal_connect (GTK_OBJECT (priv->attendee_list), "select_row",
GTK_SIGNAL_FUNC (list_row_select_cb), editor);
gtk_signal_connect (GTK_OBJECT (priv->schedule_button), "clicked",
GTK_SIGNAL_FUNC (schedule_button_clicked_cb), editor);
gtk_signal_connect (GTK_OBJECT (priv->publish_button), "clicked",
GTK_SIGNAL_FUNC (publish_button_clicked_cb), editor);
gtk_signal_connect (GTK_OBJECT (priv->request_button), "clicked",
GTK_SIGNAL_FUNC (request_button_clicked_cb), editor);
gtk_signal_connect (GTK_OBJECT (priv->cancel_button), "clicked",
GTK_SIGNAL_FUNC (cancel_button_clicked_cb), editor);
add_button = glade_xml_get_widget (priv->xml, "add_button");
delete_button = glade_xml_get_widget (priv->xml, "delete_button");
edit_button = glade_xml_get_widget (priv->xml, "edit_button");
gtk_signal_connect (GTK_OBJECT (add_button), "clicked",
GTK_SIGNAL_FUNC (add_button_clicked_cb), editor);
gtk_signal_connect (GTK_OBJECT (delete_button), "clicked",
GTK_SIGNAL_FUNC (delete_button_clicked_cb), editor);
gtk_signal_connect (GTK_OBJECT (edit_button), "clicked",
GTK_SIGNAL_FUNC (edit_button_clicked_cb), editor);
priv->organizer_entry = glade_xml_get_widget (priv->xml, "organizer_entry");
if (icalcomponent_isa (priv->icalcomp) != ICAL_VEVENT_COMPONENT) {
icalcompiter iter;
iter = icalcomponent_begin_component (priv->icalcomp, ICAL_VEVENT_COMPONENT);
priv->vevent = icalcompiter_deref (&iter);
} else
priv->vevent = priv->icalcomp;
g_assert (priv->vevent != NULL);
/* Let's extract the organizer, if there is one. */
prop = icalcomponent_get_first_property (priv->vevent, ICAL_ORGANIZER_PROPERTY);
if (prop != NULL) {
gchar *buffer;
value = icalproperty_get_value (prop);
buffer = g_strdup (icalvalue_as_ical_string (value));
if (buffer != NULL) {
/* Strip off the MAILTO:, if it is present. */
text = strchr (buffer, ':');
if (text == NULL)
text = buffer;
else
text++;
gtk_entry_set_text (GTK_ENTRY (priv->organizer_entry), text);
g_free (buffer);
}
}
priv->changed_signal_id = gtk_signal_connect (GTK_OBJECT (priv->organizer_entry), "changed",
GTK_SIGNAL_FUNC (organizer_changed_cb), editor);
/* Let's go through the iCAL object, and create a list entry
for each ATTENDEE property. */
for (prop = icalcomponent_get_first_property (priv->vevent, ICAL_ATTENDEE_PROPERTY);
prop != NULL;
prop = icalcomponent_get_next_property (priv->vevent, ICAL_ATTENDEE_PROPERTY))
{
put_property_in_list (prop, -1, editor);
}
gtk_widget_show (priv->meeting_window);
gtk_main ();
if (priv->meeting_window != NULL)
gtk_widget_destroy (priv->meeting_window);
if (priv->edit_dialog != NULL)
gtk_widget_destroy (priv->edit_dialog);
gtk_object_unref (GTK_OBJECT (priv->xml));
}