From ca603236ed6d7a43bc4587b70d6163ee1d95e310 Mon Sep 17 00:00:00 2001
From: JP Rosevear <jpr@ximian.com>
Date: Tue, 19 Jun 2001 19:24:08 +0000
Subject: itip/imip send dialog

2001-06-19  JP Rosevear  <jpr@ximian.com>

	* gui/dialogs/send-comp.c: itip/imip send dialog

	* gui/dialogs/send-comp.h: new proto

	* gui/dialogs/recurrence-page.c (recurrence_page_set_dates): only
	use the weekday picker if visible

	* gui/dialogs/meeting-page.c: just show the meeting list

	* gui/dialogs/event-editor.c (event_editor_edit_comp): remove the
	meeting page if no attendees
	(schedule_meeting_cmd): schedule a meeting menu item
	(refresh_meeting_cmd): refresh meeting request menu item
	(cancel_meeting_cmd): ditto for cancel
	(forward_cmd): send as attachment

	* gui/dialogs/comp-editor.c (comp_editor_remove_page): remove page
	from dialog
	(comp_editor_show_page): show a given page
	(comp_editor_get_current_comp): return a cal component
	representing the current widget state
	(comp_editor_save_comp): save the cal component
	(comp_editor_delete_comp): delete the cal component
	(comp_editor_send_comp): send the cal component
	(comp_editor_merge_ui): merge xml in to the bonobo gui
	(setup_widgets): use a bonobo window instead of a gtk window, add menus again
	(save_as_cmd): save to file on disk - still broken
	(save_close_cmd): close menu command
	(save_close_cmd): save and close menu command

	* gui/dialogs/comp-editor.h: new protos

	* gui/dialogs/cancel-comp.c (cancel_component_dialog): itip/imip
	cancellation dialog

	* gui/dialogs/cancel-comp.h: new proto

	* gui/dialogs/Makefile.am: build new files

	* gui/dialogs/comp-editor-page.c
	(comp_editor_page_notify_needs_send): emit needs_send signal

	* gui/dialogs/comp-editor-page.h: new signal protos

	* gui/itip-utils.c (itip_send_comp): new function to send cal
	components

	* gui/itip-utils.h: new proto

	* gui/e-itip-control.c (pstream_load): trim using cal-component
	wrapper stuff
	(accept_button_clicked_cb): use itip_send_comp
	(tentative_button_clicked_cb): ditto
	(decline_button_clicked_cb): ditto

	* gui/Makefile.am: compile select name idl stuff

	* cal-util/cal-component.c (cal_component_get_organizer): get the organizer
	(cal_component_set_organizer): set the organizer
	(cal_component_get_recurid): get the recurrence id
	(cal_component_set_recurid): set the recurrence id
	(set_attendee_list): actually set the attendee list
	(get_attendee_list): build the attendee list

	* cal-util/cal-component.h: new protos

svn path=/trunk/; revision=10299
---
 calendar/gui/dialogs/Makefile.am        |   7 +
 calendar/gui/dialogs/cancel-comp.c      |  84 ++++
 calendar/gui/dialogs/cancel-comp.h      |  30 ++
 calendar/gui/dialogs/comp-editor-page.c |  51 ++-
 calendar/gui/dialogs/comp-editor-page.h |  11 +-
 calendar/gui/dialogs/comp-editor.c      | 461 ++++++++++++++++++--
 calendar/gui/dialogs/comp-editor.h      |  42 +-
 calendar/gui/dialogs/event-editor.c     | 111 ++++-
 calendar/gui/dialogs/meeting-page.c     | 739 +++++++++++++++++++++++---------
 calendar/gui/dialogs/meeting-page.glade | 103 +++--
 calendar/gui/dialogs/recurrence-page.c  |  10 +-
 calendar/gui/dialogs/send-comp.c        |  84 ++++
 calendar/gui/dialogs/send-comp.h        |  30 ++
 13 files changed, 1439 insertions(+), 324 deletions(-)
 create mode 100644 calendar/gui/dialogs/cancel-comp.c
 create mode 100644 calendar/gui/dialogs/cancel-comp.h
 create mode 100644 calendar/gui/dialogs/send-comp.c
 create mode 100644 calendar/gui/dialogs/send-comp.h

(limited to 'calendar/gui/dialogs')

diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am
index de97ea2d45..1bd4b5034e 100644
--- a/calendar/gui/dialogs/Makefile.am
+++ b/calendar/gui/dialogs/Makefile.am
@@ -24,6 +24,8 @@ libcal_dialogs_a_SOURCES =	\
 	alarm-page.h		\
 	cal-prefs-dialog.c	\
 	cal-prefs-dialog.h	\
+	cancel-comp.c		\
+	cancel-comp.h		\
 	comp-editor.c		\
 	comp-editor.h		\
 	comp-editor-page.c	\
@@ -38,10 +40,14 @@ libcal_dialogs_a_SOURCES =	\
 	event-editor.h		\
 	event-page.c		\
 	event-page.h		\
+	meeting-page.c		\
+	meeting-page.h		\
 	recurrence-page.c	\
 	recurrence-page.h	\
 	save-comp.c		\
 	save-comp.h		\
+	send-comp.c		\
+	send-comp.h		\
 	task-editor.c		\
 	task-editor.h		\
 	task-details-page.c	\
@@ -55,6 +61,7 @@ glade_DATA =				\
 	cal-prefs-dialog.glade		\
 	e-timezone-dialog.glade		\
 	event-page.glade		\
+	meeting-page.glade		\
 	recurrence-page.glade		\
 	task-details-page.glade		\
 	task-page.glade
diff --git a/calendar/gui/dialogs/cancel-comp.c b/calendar/gui/dialogs/cancel-comp.c
new file mode 100644
index 0000000000..4362f9da7f
--- /dev/null
+++ b/calendar/gui/dialogs/cancel-comp.c
@@ -0,0 +1,84 @@
+/* Evolution calendar - Send calendar component dialog
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Author: JP Rosevear <jpr@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-uidefs.h>
+#include <gal/widgets/e-unicode.h>
+#include "cancel-comp.h"
+
+
+
+/**
+ * cancel_component_dialog:
+ * 
+ * Pops up a dialog box asking the user whether he wants to send a
+ * cancel and delete an iTip/iMip message
+ * 
+ * Return value: TRUE if the user clicked Yes, FALSE otherwise.
+ **/
+gboolean
+cancel_component_dialog (CalComponent *comp)
+{
+	GtkWidget *dialog;
+	CalComponentVType vtype;
+	char *str;
+
+	str = _("The meeting status has changed. Send an updated version?");
+
+	vtype = cal_component_get_vtype (comp);
+
+	switch (vtype) {
+	case CAL_COMPONENT_EVENT:
+		str = g_strdup_printf (_("Are you sure you want to cancel "
+					 "and delete this meeting?"));
+		break;
+
+	case CAL_COMPONENT_TODO:
+		str = g_strdup_printf (_("Are you sure you want to cancel "
+					 "and delete this task?"));
+		break;
+
+	case CAL_COMPONENT_JOURNAL:
+		str = g_strdup_printf (_("Are you sure you want to cancel "
+					 "and delete this journal entry?"));
+		break;
+
+	default:
+		g_message ("send_component_dialog(): "
+			   "Cannot handle object of type %d", vtype);
+		return FALSE;
+	}
+	
+	dialog = gnome_question_dialog_modal (str, NULL, NULL);
+
+	if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_YES)
+		return TRUE;
+	else
+		return FALSE;
+}
diff --git a/calendar/gui/dialogs/cancel-comp.h b/calendar/gui/dialogs/cancel-comp.h
new file mode 100644
index 0000000000..04f1768e3d
--- /dev/null
+++ b/calendar/gui/dialogs/cancel-comp.h
@@ -0,0 +1,30 @@
+/* Evolution calendar - Send calendar component dialog
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Author: JP Rosevear <jpr@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.
+ */
+
+#ifndef CANCEL_COMP_H
+#define CANCEL_COMP_H
+
+#include <glib.h>
+#include <cal-util/cal-component.h>
+
+gboolean cancel_component_dialog (CalComponent *comp);
+
+#endif
diff --git a/calendar/gui/dialogs/comp-editor-page.c b/calendar/gui/dialogs/comp-editor-page.c
index eab0a50566..005314d0c0 100644
--- a/calendar/gui/dialogs/comp-editor-page.c
+++ b/calendar/gui/dialogs/comp-editor-page.c
@@ -34,6 +34,7 @@ static void comp_editor_page_class_init (CompEditorPageClass *class);
 
 enum {
 	CHANGED,
+	NEEDS_SEND,
 	SUMMARY_CHANGED,
 	DATES_CHANGED,
 	LAST_SIGNAL
@@ -95,6 +96,15 @@ comp_editor_page_class_init (CompEditorPageClass *class)
 				gtk_marshal_NONE__NONE,
 				GTK_TYPE_NONE, 0);
 
+	comp_editor_page_signals[NEEDS_SEND] =
+		gtk_signal_new ("needs_send",
+				GTK_RUN_FIRST,
+				object_class->type,
+				GTK_SIGNAL_OFFSET (CompEditorPageClass,
+						   needs_send),
+				gtk_marshal_NONE__NONE,
+				GTK_TYPE_NONE, 0);
+
 	comp_editor_page_signals[SUMMARY_CHANGED] =
 		gtk_signal_new ("summary_changed",
 				GTK_RUN_FIRST,
@@ -188,6 +198,23 @@ comp_editor_page_fill_component (CompEditorPage *page, CalComponent *comp)
 		(* CLASS (page)->fill_component) (page, comp);
 }
 
+/**
+ * comp_editor_page_set_cal_client:
+ * @page: An editor page
+ * @client: A #CalClient object
+ * 
+ * Sets the #CalClient for the dialog page to use.
+ **/
+void
+comp_editor_page_set_cal_client (CompEditorPage *page, CalClient *client)
+{
+	g_return_if_fail (page != NULL);
+	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
+
+	if (CLASS (page)->set_cal_client != NULL)
+		(* CLASS (page)->set_cal_client) (page, client);
+}
+
 /**
  * comp_editor_page_set_summary:
  * @page: An editor page
@@ -223,36 +250,34 @@ comp_editor_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates)
 }
 
 /**
- * comp_editor_page_set_cal_client:
- * @page: An editor page
- * @client: A #CalClient object
+ * comp_editor_page_notify_changed:
+ * @page: An editor page.
  * 
- * Sets the #CalClient for the dialog page to use.
+ * Makes an editor page emit the "changed" signal.  This is meant to be
+ * used only by page implementations.
  **/
 void
-comp_editor_page_set_cal_client (CompEditorPage *page, CalClient *client)
+comp_editor_page_notify_changed (CompEditorPage *page)
 {
 	g_return_if_fail (page != NULL);
 	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
 
-	if (CLASS (page)->set_cal_client != NULL)
-		(* CLASS (page)->set_cal_client) (page, client);
+	gtk_signal_emit (GTK_OBJECT (page), comp_editor_page_signals[CHANGED]);
 }
 
 /**
- * comp_editor_page_notify_changed:
- * @page: An editor page.
+ * comp_editor_page_notify_needs_send:
+ * @page: 
+ * 
  * 
- * Makes an editor page emit the "changed" signal.  This is meant to be
- * used only by page implementations.
  **/
 void
-comp_editor_page_notify_changed (CompEditorPage *page)
+comp_editor_page_notify_needs_send (CompEditorPage *page)
 {
 	g_return_if_fail (page != NULL);
 	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
 
-	gtk_signal_emit (GTK_OBJECT (page), comp_editor_page_signals[CHANGED]);
+	gtk_signal_emit (GTK_OBJECT (page), comp_editor_page_signals[NEEDS_SEND]);	
 }
 
 /**
diff --git a/calendar/gui/dialogs/comp-editor-page.h b/calendar/gui/dialogs/comp-editor-page.h
index 931aa32d62..c4c31852cf 100644
--- a/calendar/gui/dialogs/comp-editor-page.h
+++ b/calendar/gui/dialogs/comp-editor-page.h
@@ -54,9 +54,11 @@ typedef struct {
 
 	/* Notification signals */
 
-	void (* changed) (CompEditorPage *page);
+	void (* changed)    (CompEditorPage *page);
+	void (* needs_send) (CompEditorPage *page);
+
 	void (* summary_changed) (CompEditorPage *page, const char *summary);
-	void (* dates_changed) (CompEditorPage *page, const char *dates);
+	void (* dates_changed)   (CompEditorPage *page, const char *dates);
 
 	/* Virtual methods */
 
@@ -78,13 +80,14 @@ void       comp_editor_page_fill_widgets           (CompEditorPage      *page,
 						    CalComponent        *comp);
 void       comp_editor_page_fill_component         (CompEditorPage      *page,
 						    CalComponent        *comp);
+void       comp_editor_page_set_cal_client         (CompEditorPage      *page,
+						    CalClient		*client);
 void       comp_editor_page_set_summary            (CompEditorPage      *page,
 						    const char          *summary);
 void       comp_editor_page_set_dates              (CompEditorPage      *page,
 						    CompEditorPageDates *dates);
-void       comp_editor_page_set_cal_client         (CompEditorPage      *page,
-						    CalClient		*client);
 void       comp_editor_page_notify_changed         (CompEditorPage      *page);
+void       comp_editor_page_notify_needs_send      (CompEditorPage      *page);
 void       comp_editor_page_notify_summary_changed (CompEditorPage      *page,
 						    const char          *summary);
 void       comp_editor_page_notify_dates_changed   (CompEditorPage      *page,
diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c
index 2d894f3ff2..5347a40df3 100644
--- a/calendar/gui/dialogs/comp-editor.c
+++ b/calendar/gui/dialogs/comp-editor.c
@@ -23,9 +23,18 @@
 #include <config.h>
 #endif
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <gnome.h>
+#include <bonobo/bonobo-win.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <bonobo/bonobo-ui-container.h>
+#include <bonobo/bonobo-ui-util.h>
 #include <gal/widgets/e-unicode.h>
 #include "save-comp.h"
+#include "delete-comp.h"
+#include "send-comp.h"
 #include "comp-editor.h"
 
 
@@ -43,11 +52,15 @@ struct _CompEditorPrivate {
 
 	/* Toplevel window for the dialog */
 	GtkWidget *window;
-
+	BonoboUIComponent *uic;
+	
 	/* Notebook to hold the pages */
 	GtkNotebook *notebook;
 
+	GtkWidget *filesel;
+	
 	gboolean changed;
+	gboolean needs_send;
 };
 
 
@@ -56,15 +69,37 @@ static void comp_editor_class_init (CompEditorClass *class);
 static void comp_editor_init (CompEditor *editor);
 static void comp_editor_destroy (GtkObject *object);
 
+static void real_edit_comp (CompEditor *editor, CalComponent *comp);
+static void save_comp (CompEditor *editor);
+static void delete_comp (CompEditor *editor);
+static void close_dialog (CompEditor *editor);
+
+static void page_changed_cb (GtkWidget *widget, gpointer data);
+static void page_needs_send_cb (GtkWidget *widget, gpointer data);
 static void page_summary_changed_cb (GtkWidget *widget, const char *summary, gpointer data);
 static void page_dates_changed_cb (GtkWidget *widget, CompEditorPageDates *dates, gpointer data);
-static void page_changed_cb (GtkWidget *widget, gpointer data);
+
+static void save_close_cmd (GtkWidget *widget, gpointer data);
+static void save_as_cmd (GtkWidget *widget, gpointer data);
+static void delete_cmd (GtkWidget *widget, gpointer data);
+static void close_cmd (GtkWidget *widget, gpointer data);
 
 static void save_clicked_cb (GtkWidget *widget, gpointer data);
 static void close_clicked_cb (GtkWidget *widget, gpointer data);
 static void help_clicked_cb (GtkWidget *widget, gpointer data);
 static gint delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data);
 
+static BonoboUIVerb verbs [] = {
+	BONOBO_UI_UNSAFE_VERB ("FileSaveAndClose", save_close_cmd), 
+	BONOBO_UI_UNSAFE_VERB ("FileSaveAs", save_as_cmd),
+	BONOBO_UI_UNSAFE_VERB ("FileDelete", delete_cmd), 
+	BONOBO_UI_UNSAFE_VERB ("FileClose", close_cmd), 
+	
+	BONOBO_UI_VERB_END
+};
+
+#define CLASS(page) (COMP_EDITOR_CLASS (GTK_OBJECT (page)->klass))
+
 static GtkObjectClass *parent_class;
 
 
@@ -95,14 +130,16 @@ comp_editor_get_type (void)
 
 /* Class initialization function for the calendar component editor */
 static void
-comp_editor_class_init (CompEditorClass *class)
+comp_editor_class_init (CompEditorClass *klass)
 {
 	GtkObjectClass *object_class;
 
-	object_class = (GtkObjectClass *) class;
+	object_class = (GtkObjectClass *) klass;
 
 	parent_class = gtk_type_class (GTK_TYPE_OBJECT);
 
+	klass->edit_comp = real_edit_comp;
+
 	object_class->destroy = comp_editor_destroy;
 }
 
@@ -111,6 +148,7 @@ static void
 setup_widgets (CompEditor *editor)
 {
 	CompEditorPrivate *priv;
+	BonoboUIContainer *container;
 	GtkWidget *vbox;
 	GtkWidget *bbox;
 	GtkWidget *pixmap;
@@ -119,23 +157,29 @@ setup_widgets (CompEditor *editor)
 	priv = editor->priv;
 
 	/* Window and basic vbox */
-
-	priv->window = gtk_window_new (GTK_WINDOW_DIALOG);
+	priv->window = bonobo_window_new ("event-editor", "iCalendar Editor");
 	gtk_signal_connect (GTK_OBJECT (priv->window), "delete_event",
 			    GTK_SIGNAL_FUNC (delete_event_cb), editor);
 
+	priv->uic = bonobo_ui_component_new ("comp-editor");
+	container = bonobo_ui_container_new ();
+	bonobo_ui_container_set_win (container, BONOBO_WINDOW (priv->window));
+	bonobo_ui_component_set_container (priv->uic, BONOBO_OBJREF (container));
+
+	bonobo_ui_component_add_verb_list_with_data (priv->uic, verbs, editor);
+	bonobo_ui_util_set_ui (priv->uic, EVOLUTION_DATADIR "/gnome/gui",
+			       "evolution-comp-editor.xml", "evolution-calendar");
+
 	vbox = gtk_vbox_new (FALSE, GNOME_PAD_SMALL);
 	gtk_container_set_border_width (GTK_CONTAINER (vbox), GNOME_PAD_SMALL);
-	gtk_container_add (GTK_CONTAINER (priv->window), vbox);
+	bonobo_window_set_contents (BONOBO_WINDOW (priv->window), vbox);
 
 	/* Notebook */
-
 	priv->notebook = GTK_NOTEBOOK (gtk_notebook_new ());
 	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->notebook),
 			    TRUE, TRUE, 0);
 
 	/* Buttons */
-
 	bbox = gtk_hbutton_box_new ();
 	gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
 	gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
@@ -170,6 +214,7 @@ comp_editor_init (CompEditor *editor)
 
 	priv->pages = NULL;
 	priv->changed = FALSE;
+	priv->needs_send = FALSE;
 }
 
 /* Destroy handler for the calendar component editor */
@@ -199,7 +244,7 @@ comp_editor_destroy (GtkObject *object)
 /**
  * comp_editor_append_page:
  * @editor: A component editor
- * @page: Top level widget of the page
+ * @page: A component editor page
  * @label: Label of the page
  * 
  * Appends a page to the editor notebook with the given label
@@ -212,7 +257,7 @@ comp_editor_append_page (CompEditor *editor,
 	CompEditorPrivate *priv;
 	GtkWidget *page_widget;
 	GtkWidget *label_widget;
-
+	
 	g_return_if_fail (editor != NULL);
 	g_return_if_fail (IS_COMP_EDITOR (editor));
 	g_return_if_fail (page != NULL);
@@ -221,9 +266,15 @@ comp_editor_append_page (CompEditor *editor,
 
 	priv = editor->priv;
 
-	/* Only allow adding the pages while a component has not been set */
-	g_return_if_fail (priv->comp == NULL);
-
+	/* If we are editing something, fill the widgets with current info */
+	if (priv->comp != NULL) {
+		CalComponent *comp;
+		
+		comp = comp_editor_get_current_comp (editor);
+		comp_editor_page_fill_widgets (page, comp);
+		gtk_object_unref (GTK_OBJECT (comp));
+	}
+	
 	page_widget = comp_editor_page_get_widget (page);
 	g_assert (page_widget != NULL);
 	
@@ -233,12 +284,67 @@ comp_editor_append_page (CompEditor *editor,
 	gtk_notebook_append_page (priv->notebook, page_widget, label_widget);
 
 	/* Listen for things happening on the page */
+	gtk_signal_connect (GTK_OBJECT (page), "needs_send",
+			    GTK_SIGNAL_FUNC (page_needs_send_cb), editor);
+	gtk_signal_connect (GTK_OBJECT (page), "changed",
+			    GTK_SIGNAL_FUNC (page_changed_cb), editor);
 	gtk_signal_connect (GTK_OBJECT (page), "summary_changed",
 			    GTK_SIGNAL_FUNC (page_summary_changed_cb), editor);
 	gtk_signal_connect (GTK_OBJECT (page), "dates_changed",
 			    GTK_SIGNAL_FUNC (page_dates_changed_cb), editor);
-	gtk_signal_connect (GTK_OBJECT (page), "changed",
-			    GTK_SIGNAL_FUNC (page_changed_cb), editor);
+
+}
+
+/**
+ * comp_editor_remove_page:
+ * @editor: A component editor
+ * @page: A component editor page
+ * 
+ * Removes the page from the component editor
+ **/
+void
+comp_editor_remove_page (CompEditor *editor, CompEditorPage *page)
+{
+	CompEditorPrivate *priv;
+	GtkWidget *page_widget;
+	gint page_num;
+	
+	g_return_if_fail (editor != NULL);
+	g_return_if_fail (IS_COMP_EDITOR (editor));
+	g_return_if_fail (page != NULL);
+	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
+
+	priv = editor->priv;
+	
+	page_widget = comp_editor_page_get_widget (page);
+	page_num = gtk_notebook_page_num (priv->notebook, page_widget);
+	gtk_notebook_remove_page (priv->notebook, page_num);
+}
+
+/**
+ * comp_editor_show_page:
+ * @editor: 
+ * @page: 
+ * 
+ * 
+ **/
+void
+comp_editor_show_page (CompEditor *editor, CompEditorPage *page)
+{
+	CompEditorPrivate *priv;
+	GtkWidget *page_widget;
+	gint page_num;
+	
+	g_return_if_fail (editor != NULL);
+	g_return_if_fail (IS_COMP_EDITOR (editor));
+	g_return_if_fail (page != NULL);
+	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
+
+	priv = editor->priv;
+	
+	page_widget = comp_editor_page_get_widget (page);
+	page_num = gtk_notebook_page_num (priv->notebook, page_widget);
+	gtk_notebook_set_page (priv->notebook, page_num);
 }
 
 /**
@@ -368,15 +474,8 @@ fill_widgets (CompEditor *editor)
 		comp_editor_page_fill_widgets (l->data, priv->comp);
 }
 
-/**
- * comp_editor_edit_comp:
- * @editor: A component editor
- * @comp: A calendar component
- * 
- * Starts the editor editing the given component
- **/
-void
-comp_editor_edit_comp (CompEditor *editor, CalComponent *comp)
+static void
+real_edit_comp (CompEditor *editor, CalComponent *comp) 
 {
 	CompEditorPrivate *priv;
 
@@ -394,9 +493,124 @@ comp_editor_edit_comp (CompEditor *editor, CalComponent *comp)
 		priv->comp = cal_component_clone (comp);
 
 	set_title_from_comp (editor);
-	fill_widgets (editor);
+	fill_widgets (editor);	
 }
 
+	
+/**
+ * comp_editor_edit_comp:
+ * @editor: A component editor
+ * @comp: A calendar component
+ * 
+ * Starts the editor editing the given component
+ **/
+void
+comp_editor_edit_comp (CompEditor *editor, CalComponent *comp)
+{
+	CompEditorClass *klass;
+	
+	g_return_if_fail (editor != NULL);
+	g_return_if_fail (IS_COMP_EDITOR (editor));
+	g_return_if_fail (comp != NULL);
+	g_return_if_fail (IS_CAL_COMPONENT (comp));
+
+	klass = COMP_EDITOR_CLASS (GTK_OBJECT (editor)->klass);
+	
+	if (klass->edit_comp)
+		klass->edit_comp (editor, comp);
+}
+
+CalComponent *
+comp_editor_get_current_comp (CompEditor *editor)
+{	
+	CompEditorPrivate *priv;	
+	CalComponent *comp;
+	GList *l;
+	
+	g_return_val_if_fail (editor != NULL, NULL);
+	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
+
+	priv = editor->priv;
+
+	comp = cal_component_clone (priv->comp);
+	for (l = priv->pages; l != NULL; l = l->next)
+		comp_editor_page_fill_component (l->data, comp);
+
+	return comp;
+}
+
+/**
+ * comp_editor_save_comp:
+ * @editor: 
+ * 
+ * 
+ **/
+void
+comp_editor_save_comp (CompEditor *editor)
+{
+	save_comp (editor);
+}
+
+/**
+ * comp_editor_delete_comp:
+ * @editor: 
+ * 
+ * 
+ **/
+void
+comp_editor_delete_comp (CompEditor *editor)
+{
+	delete_comp (editor);
+}
+
+/**
+ * comp_editor_send_comp:
+ * @editor: 
+ * @method: 
+ * 
+ * 
+ **/
+void
+comp_editor_send_comp (CompEditor *editor, CalComponentItipMethod method)
+{
+	CalComponent *comp;
+
+	comp = comp_editor_get_current_comp (editor);
+
+	cal_component_commit_sequence (comp);
+	itip_send_comp (method, comp);
+
+	gtk_object_unref (GTK_OBJECT (comp));
+}
+
+/**
+ * comp_editor_merge_ui:
+ * @editor: 
+ * @filename: 
+ * @verbs: 
+ * 
+ * 
+ **/
+void
+comp_editor_merge_ui (CompEditor *editor, const char *filename, BonoboUIVerb *verbs)
+{
+	CompEditorPrivate *priv;
+	BonoboUIEngine *engine;
+	BonoboUINode *node;
+	
+	g_return_if_fail (editor != NULL);
+	g_return_if_fail (IS_COMP_EDITOR (editor));
+	
+	priv = editor->priv;
+
+	engine = bonobo_window_get_ui_engine (BONOBO_WINDOW (priv->window));
+	node = bonobo_ui_util_new_ui (priv->uic, filename, "",
+				      "evolution-calendar");
+	g_assert (node != NULL);
+
+	bonobo_ui_engine_xml_merge_tree (engine, "/", node, "comp-editor");
+	bonobo_ui_component_add_verb_list_with_data (priv->uic, verbs, editor);
+}
 
 /* Brings attention to a window by raising it and giving it focus */
 static void
@@ -438,17 +652,35 @@ save_comp (CompEditor *editor)
 	for (l = priv->pages; l != NULL; l = l->next)
 		comp_editor_page_fill_component (l->data, priv->comp);
 
+	if (priv->needs_send && send_component_dialog (priv->comp)) {
+		cal_component_commit_sequence (priv->comp);
+		itip_send_comp (CAL_COMPONENT_METHOD_REQUEST, priv->comp);
+	}
+	
 	if (!cal_client_update_object (priv->client, priv->comp))
 		g_message ("save_comp (): Could not update the object!");
 	else
 		priv->changed = FALSE;
 }
 
+static void
+delete_comp (CompEditor *editor)
+{
+	CompEditorPrivate *priv;
+	const char *uid;
+
+	priv = editor->priv;
+
+	cal_component_get_uid (priv->comp, &uid);
+	cal_client_remove_object (priv->client, uid);
+	close_dialog (editor);
+}
+
 static gboolean
 prompt_to_save_changes (CompEditor *editor)
 {
 	CompEditorPrivate *priv;
-
+	
 	priv = editor->priv;
 
 	if (!priv->changed)
@@ -465,7 +697,6 @@ prompt_to_save_changes (CompEditor *editor)
 	case 2: /* Cancel */
 	default:
 		return FALSE;
-		break;
 	}
 }
 
@@ -482,6 +713,144 @@ close_dialog (CompEditor *editor)
 	gtk_object_destroy (GTK_OBJECT (editor));
 }
 
+/* Menu Commands */
+static void
+save_close_cmd (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+
+	save_comp (editor);
+	close_dialog (editor);
+}
+
+static void
+save_as_ok (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+	CompEditorPrivate *priv;
+	char *path;
+	int fd, ret = 0;
+	
+	priv = editor->priv;
+	
+	path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (priv->filesel));
+	
+        fd = open (path, O_RDONLY);
+	if (fd != -1) {
+		GtkWidget *dlg;
+		GtkWidget *text;
+		
+		close (fd);
+		
+		dlg = gnome_dialog_new (_("Overwrite file?"),
+					GNOME_STOCK_BUTTON_YES, 
+					GNOME_STOCK_BUTTON_NO,
+					NULL);
+		text = gtk_label_new (_("A file by that name already exists.\nOverwrite it?"));
+		gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dlg)->vbox), text, TRUE, TRUE, 4);
+		gtk_window_set_policy (GTK_WINDOW (dlg), FALSE, TRUE, FALSE);
+		gtk_widget_show (text);
+		
+		ret = gnome_dialog_run_and_close (GNOME_DIALOG (dlg));
+	}
+	
+	if (ret == 0) {
+		gchar *ical_string;
+
+		icalcomponent *top_level;
+		icalcomponent *icalcomp;
+		icalproperty *prop;
+
+		top_level = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
+
+		/* RFC 2445, section 4.7.1 */
+		prop = icalproperty_new_calscale ("GREGORIAN");
+		icalcomponent_add_property (top_level, prop);
+		
+		/* RFC 2445, section 4.7.3 */
+		prop = icalproperty_new_prodid ("-//Ximian//NONSGML Evolution Calendar//EN");
+		icalcomponent_add_property (top_level, prop);
+		
+		/* RFC 2445, section 4.7.4.  This is the iCalendar spec version, *NOT*
+		 * the product version!  Do not change this!
+		 */
+		prop = icalproperty_new_version ("2.0");
+		icalcomponent_add_property (top_level, prop);
+				
+		icalcomp = cal_component_get_icalcomponent (priv->comp);
+		g_assert (icalcomp != NULL);
+
+		icalcomponent_add_component (top_level, icalcomp);
+		
+		ical_string = icalcomponent_as_ical_string (top_level);
+
+		fd = open (path, O_WRONLY);
+		if (fd == -1) {			
+			g_warning ("Couldn't save item");
+			gtk_main_quit ();
+			return;
+		}
+		
+		write (fd, ical_string, strlen (ical_string));
+		close (fd);
+
+		gtk_main_quit ();
+	}
+}
+
+static void
+save_as_cmd (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+	CompEditorPrivate *priv;
+	GtkFileSelection *fs;
+	char *path;
+	
+	priv = editor->priv;
+	
+	fs = GTK_FILE_SELECTION (gtk_file_selection_new (_("Save As...")));
+	path = g_strdup_printf ("%s/", g_get_home_dir ());
+	gtk_file_selection_set_filename (fs, path);
+	g_free (path);
+
+	gtk_signal_connect (GTK_OBJECT (fs->ok_button), "clicked", 
+			    GTK_SIGNAL_FUNC (save_as_ok), editor);
+	gtk_signal_connect (GTK_OBJECT (fs->cancel_button), "clicked", 
+			    GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+	
+	priv->filesel = GTK_WIDGET (fs);
+	gtk_widget_show (priv->filesel);
+	gtk_grab_add (priv->filesel);
+	gtk_main ();
+
+	gtk_widget_destroy (priv->filesel);
+	priv->filesel = NULL;
+}
+
+static void
+delete_cmd (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+	CompEditorPrivate *priv;
+	CalComponentVType vtype;
+
+	priv = editor->priv;
+	
+	vtype = cal_component_get_vtype (priv->comp);
+
+	if (delete_component_dialog (priv->comp, 1, vtype, priv->window))
+		delete_comp (editor);
+}
+
+static void
+close_cmd (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+
+	if (prompt_to_save_changes (editor))
+		close_dialog (editor);
+}
+
 static void
 save_clicked_cb (GtkWidget *widget, gpointer data)
 {
@@ -500,11 +869,35 @@ close_clicked_cb (GtkWidget *widget, gpointer data)
 		close_dialog (editor);
 }
 
+/* Button callbacks */
 static void
 help_clicked_cb (GtkWidget *widget, gpointer data)
 {
 }
 
+static void
+page_changed_cb (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+	CompEditorPrivate *priv;
+	
+	priv = editor->priv;
+	
+	priv->changed = TRUE;
+}
+
+static void
+page_needs_send_cb (GtkWidget *widget, gpointer data)
+{
+	CompEditor *editor = COMP_EDITOR (data);
+	CompEditorPrivate *priv;
+	
+	priv = editor->priv;
+	
+	priv->needs_send = TRUE;	
+}
+
+/* Page signal callbacks */
 static void
 page_summary_changed_cb (GtkWidget *widget, const char *summary, gpointer data)
 {
@@ -537,18 +930,6 @@ page_dates_changed_cb (GtkWidget *widget,
 	priv->changed = TRUE;
 }
 
-
-static void
-page_changed_cb (GtkWidget *widget, gpointer data)
-{
-	CompEditor *editor = COMP_EDITOR (data);
-	CompEditorPrivate *priv;
-	
-	priv = editor->priv;
-	
-	priv->changed = TRUE;
-}
-
 static gint
 delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
 {
diff --git a/calendar/gui/dialogs/comp-editor.h b/calendar/gui/dialogs/comp-editor.h
index 225abeac3c..cf24a2befb 100644
--- a/calendar/gui/dialogs/comp-editor.h
+++ b/calendar/gui/dialogs/comp-editor.h
@@ -23,7 +23,10 @@
 #define COMP_EDITOR_H
 
 #include <gtk/gtk.h>
+#include <bonobo/bonobo-ui-engine.h>
+#include <bonobo/bonobo-ui-component.h>
 #include "cal-client.h"
+#include "../itip-utils.h"
 #include "comp-editor-page.h"
 
 BEGIN_GNOME_DECLS
@@ -47,19 +50,36 @@ typedef struct {
 
 typedef struct {
 	GtkObjectClass parent_class;
+
+	/* Virtual functions */
+	void (* edit_comp) (CompEditor *page, CalComponent *comp);
 } CompEditorClass;
+GtkType       comp_editor_get_type         (void);
+CompEditor   *comp_editor_new              (void);
+void          comp_editor_append_page      (CompEditor             *editor,
+					    CompEditorPage         *page,
+					    const char             *label);
+void          comp_editor_remove_page      (CompEditor             *editor,
+					    CompEditorPage         *page);
+void          comp_editor_show_page        (CompEditor             *editor,
+					    CompEditorPage         *page);
+void          comp_editor_set_cal_client   (CompEditor             *editor,
+					    CalClient              *client);
+CalClient    *comp_editor_get_cal_client   (CompEditor             *editor);
+void          comp_editor_edit_comp        (CompEditor             *ee,
+					    CalComponent           *comp);
+CalComponent *comp_editor_get_current_comp (CompEditor             *editor);
+void          comp_editor_save_comp        (CompEditor             *editor);
+void          comp_editor_delete_comp      (CompEditor             *editor);
+void          comp_editor_send_comp        (CompEditor             *editor,
+					    CalComponentItipMethod  method);
+void          comp_editor_merge_ui         (CompEditor             *editor,
+					    const char             *filename,
+					    BonoboUIVerb           *verbs);
+void          comp_editor_focus            (CompEditor             *editor);
+
+
 
-GtkType     comp_editor_get_type       (void);
-CompEditor *comp_editor_new            (void);
-void        comp_editor_append_page    (CompEditor     *editor,
-					CompEditorPage *page,
-					const char     *label);
-void        comp_editor_set_cal_client (CompEditor     *editor,
-					CalClient      *client);
-CalClient * comp_editor_get_cal_client (CompEditor     *editor);
-void        comp_editor_edit_comp      (CompEditor     *ee,
-					CalComponent   *comp);
-void        comp_editor_focus          (CompEditor     *editor);
 
 
 
diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c
index b53efe12aa..36c06ff1f1 100644
--- a/calendar/gui/dialogs/event-editor.c
+++ b/calendar/gui/dialogs/event-editor.c
@@ -34,21 +34,41 @@
 #include "event-page.h"
 #include "alarm-page.h"
 #include "recurrence-page.h"
+#include "meeting-page.h"
+#include "cancel-comp.h"
 #include "event-editor.h"
 
 struct _EventEditorPrivate {
 	EventPage *event_page;
 	AlarmPage *alarm_page;
 	RecurrencePage *recur_page;
+	MeetingPage *meet_page;
+	
+	gboolean meeting_shown;
 };
 
 
 
 static void event_editor_class_init (EventEditorClass *class);
 static void event_editor_init (EventEditor *ee);
+static void event_editor_edit_comp (CompEditor *editor, CalComponent *comp);
 static void event_editor_destroy (GtkObject *object);
 
-static CompEditor *parent_class;
+static void schedule_meeting_cmd (GtkWidget *widget, gpointer data);
+static void refresh_meeting_cmd (GtkWidget *widget, gpointer data);
+static void cancel_meeting_cmd (GtkWidget *widget, gpointer data);
+static void forward_cmd (GtkWidget *widget, gpointer data);
+
+static BonoboUIVerb verbs [] = {
+	BONOBO_UI_UNSAFE_VERB ("ActionScheduleMeeting", schedule_meeting_cmd),
+	BONOBO_UI_UNSAFE_VERB ("ActionRefreshMeeting", refresh_meeting_cmd),
+	BONOBO_UI_UNSAFE_VERB ("ActionCancelMeeting", cancel_meeting_cmd),
+	BONOBO_UI_UNSAFE_VERB ("ActionForward", forward_cmd),
+
+	BONOBO_UI_VERB_END
+};
+
+static CompEditorClass *parent_class;
 
 
 
@@ -86,14 +106,18 @@ event_editor_get_type (void)
 
 /* Class initialization function for the event editor */
 static void
-event_editor_class_init (EventEditorClass *class)
+event_editor_class_init (EventEditorClass *klass)
 {
 	GtkObjectClass *object_class;
-
-	object_class = (GtkObjectClass *) class;
+	CompEditorClass *editor_class;
+	
+	object_class = (GtkObjectClass *) klass;
+	editor_class = (CompEditorClass *) klass;
 
 	parent_class = gtk_type_class (TYPE_COMP_EDITOR);
 
+	editor_class->edit_comp = event_editor_edit_comp;
+	
 	object_class->destroy = event_editor_destroy;
 }
 
@@ -120,7 +144,37 @@ event_editor_init (EventEditor *ee)
 	comp_editor_append_page (COMP_EDITOR (ee),
 				 COMP_EDITOR_PAGE (priv->recur_page),
 				 _("Recurrence"));
+
+	priv->meet_page = meeting_page_new ();
+	comp_editor_append_page (COMP_EDITOR (ee),
+				 COMP_EDITOR_PAGE (priv->meet_page),
+				 _("Meeting"));
+
+	priv->meeting_shown = TRUE;
+	
+	comp_editor_merge_ui (COMP_EDITOR (ee), EVOLUTION_DATADIR 
+			      "/gnome/ui/evolution-event-editor.xml",
+			      verbs);
+}
+
+static void
+event_editor_edit_comp (CompEditor *editor, CalComponent *comp)
+{
+	EventEditor *ee;
+	EventEditorPrivate *priv;
+	GSList *attendees = NULL;
 	
+	ee = EVENT_EDITOR (editor);
+	priv = ee->priv;
+	
+	cal_component_get_attendee_list (comp, &attendees);
+	if (attendees == NULL) {
+		comp_editor_remove_page (editor, COMP_EDITOR_PAGE (priv->meet_page));
+		priv->meeting_shown = FALSE;
+	}
+		
+	if (parent_class->edit_comp)
+		parent_class->edit_comp (editor, comp);
 }
 
 /* Destroy handler for the event editor */
@@ -153,3 +207,52 @@ event_editor_new (void)
 {
 	return EVENT_EDITOR (gtk_type_new (TYPE_EVENT_EDITOR));
 }
+
+static void
+schedule_meeting_cmd (GtkWidget *widget, gpointer data)
+{
+	EventEditor *ee = EVENT_EDITOR (data);
+	EventEditorPrivate *priv;
+
+	priv = ee->priv;
+
+	if (!priv->meeting_shown) {
+		comp_editor_append_page (COMP_EDITOR (ee),
+					 COMP_EDITOR_PAGE (priv->meet_page),
+					 _("Meeting"));
+		priv->meeting_shown = FALSE;
+	}
+	
+	comp_editor_show_page (COMP_EDITOR (ee),
+			       COMP_EDITOR_PAGE (priv->meet_page));
+}
+
+static void
+refresh_meeting_cmd (GtkWidget *widget, gpointer data)
+{
+	EventEditor *ee = EVENT_EDITOR (data);
+	
+	comp_editor_send_comp (COMP_EDITOR (ee), CAL_COMPONENT_METHOD_REFRESH);
+}
+
+static void
+cancel_meeting_cmd (GtkWidget *widget, gpointer data)
+{
+	EventEditor *ee = EVENT_EDITOR (data);
+	CalComponent *comp;
+	
+	comp = comp_editor_get_current_comp (COMP_EDITOR (ee));
+	if (cancel_component_dialog (comp)) {
+		comp_editor_send_comp (COMP_EDITOR (ee), CAL_COMPONENT_METHOD_CANCEL);
+		comp_editor_delete_comp (COMP_EDITOR (ee));
+	}
+}
+
+static void
+forward_cmd (GtkWidget *widget, gpointer data)
+{
+	EventEditor *ee = EVENT_EDITOR (data);
+	
+	comp_editor_send_comp (COMP_EDITOR (ee), CAL_COMPONENT_METHOD_PUBLISH);
+}
+
diff --git a/calendar/gui/dialogs/meeting-page.c b/calendar/gui/dialogs/meeting-page.c
index a369646ab4..7932fbd177 100644
--- a/calendar/gui/dialogs/meeting-page.c
+++ b/calendar/gui/dialogs/meeting-page.c
@@ -27,13 +27,16 @@
 #endif
 
 #include <liboaf/liboaf.h>
-#include <gtk/gtknotebook.h>
-#include <gtk/gtkradiobutton.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-widget.h>
 #include <gtk/gtksignal.h>
-#include <gtk/gtktable.h>
 #include <gtk/gtktogglebutton.h>
 #include <gtk/gtkvbox.h>
 #include <glade/glade.h>
+#include <gal/e-table/e-cell-combo.h>
+#include <gal/e-table/e-cell-text.h>
+#include <gal/e-table/e-table-simple.h>
+#include <gal/e-table/e-table-scrolled.h>
 #include <gal/widgets/e-unicode.h>
 #include <widgets/misc/e-dateedit.h>
 #include <widgets/meeting-time-sel/e-meeting-time-sel.h>
@@ -45,21 +48,72 @@
 
 #define SELECT_NAMES_OAFID "OAFIID:GNOME_Evolution_Addressbook_SelectNames"
 
+#define MEETING_PAGE_TABLE_SPEC						\
+	"<ETableSpecification click-to-add=\"true\" "			\
+	" _click-to-add-message=\"Click here to add an attendee\" "	\
+	" draw-grid=\"true\">"						\
+        "  <ETableColumn model_col= \"0\" _title=\"Attendee\" "	\
+	"   expansion=\"1.0\" minimum_width=\"10\" resizable=\"true\" "	\
+	"   cell=\"string\" compare=\"string\"/>"			                \
+        "  <ETableColumn model_col= \"1\" _title=\"Role\" "	\
+	"   expansion=\"1.0\" minimum_width=\"10\" resizable=\"true\" "	\
+	"   cell=\"roleedit\"   compare=\"string\"/>"		\
+        "  <ETableColumn model_col= \"2\" _title=\"RSVP\" "	\
+	"   expansion=\"2.0\" minimum_width=\"10\" resizable=\"true\" "	\
+	"   cell=\"rsvpedit\" compare=\"string\"/>"			                \
+        "  <ETableColumn model_col= \"3\" _title=\"Status\" "		\
+	"   expansion=\"2.0\" minimum_width=\"10\" resizable=\"true\" "	\
+	"   cell=\"statusedit\" compare=\"string\"/>"			                \
+	"  <ETableState>"						\
+	"    <column source=\"0\"/>"					\
+	"    <column source=\"1\"/>"					\
+	"    <column source=\"2\"/>"					\
+	"    <column source=\"3\"/>"					\
+	"    <grouping></grouping>"					\
+	"  </ETableState>"						\
+	"</ETableSpecification>"
+
+enum columns {
+	MEETING_ATTENDEE_COL,
+	MEETING_ROLE_COL,
+	MEETING_RSVP_COL,
+	MEETING_STATUS_COL,
+	MEETING_COLUMN_COUNT
+};
+
+struct attendee {
+	char *address;
+	char *member;
+
+	CalComponentCUType cutype;
+	CalComponentRole role;
+	CalComponentPartStat status;
+	gboolean rsvp;
+
+	char *delto;
+	char *delfrom;
+	char *sentby;
+	char *cn;
+	char *language;
+};
+
 /* Private part of the MeetingPage structure */
 struct _MeetingPagePrivate {
+	/* List of attendees */
+	GSList *attendees;
+	
 	/* Glade XML data */
 	GladeXML *xml;
 
 	/* Widgets from the Glade file */
 	GtkWidget *main;
-
-	EMeetingTimeSelector *selector;
-	GtkWidget *table;
-	
-	/* Other widgets */
-	GtkWidget *rb1[2];
-	GtkWidget *rb2[2];
+	GtkWidget *organizer;
+	GtkWidget *invite;
 	
+	/* E Table stuff */
+	ETableModel *model;
+	GtkWidget *etable;
+
 	/* For handling the invite button */
 	GNOME_Evolution_Addressbook_SelectNames corba_select_names;
 
@@ -75,8 +129,8 @@ static void meeting_page_destroy (GtkObject *object);
 static GtkWidget *meeting_page_get_widget (CompEditorPage *page);
 static void meeting_page_fill_widgets (CompEditorPage *page, CalComponent *comp);
 static void meeting_page_fill_component (CompEditorPage *page, CalComponent *comp);
-static void meeting_page_set_summary (CompEditorPage *page, const char *summary);
-static void meeting_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates);
+
+static int row_count (ETableModel *etm, void *data);
 
 static CompEditorPageClass *parent_class = NULL;
 
@@ -130,8 +184,8 @@ meeting_page_class_init (MeetingPageClass *class)
 	editor_page_class->get_widget = meeting_page_get_widget;
 	editor_page_class->fill_widgets = meeting_page_fill_widgets;
 	editor_page_class->fill_component = meeting_page_fill_component;
-	editor_page_class->set_summary = meeting_page_set_summary;
-	editor_page_class->set_dates = meeting_page_set_dates;
+	editor_page_class->set_summary = NULL;
+	editor_page_class->set_dates = NULL;
 
 	object_class->destroy = meeting_page_destroy;
 }
@@ -148,8 +202,11 @@ meeting_page_init (MeetingPage *mpage)
 	priv->xml = NULL;
 
 	priv->main = NULL;
-	priv->selector = NULL;
-
+	priv->invite = NULL;
+	
+	priv->model = NULL;
+	priv->etable = NULL;
+	
 	priv->updating = FALSE;
 }
 
@@ -208,8 +265,9 @@ meeting_page_fill_widgets (CompEditorPage *page, CalComponent *comp)
 {
 	MeetingPage *mpage;
 	MeetingPagePrivate *priv;
-	CalComponentDateTime dtstart, dtend;
-	struct icaltimetype start, end;
+	CalComponentOrganizer organizer;
+	GSList *attendees, *l;
+	
 	mpage = MEETING_PAGE (page);
 	priv = mpage->priv;
 
@@ -217,25 +275,39 @@ meeting_page_fill_widgets (CompEditorPage *page, CalComponent *comp)
 	
 	/* Clean the screen */
 	clear_widgets (mpage);
+
+	cal_component_get_organizer (comp, &organizer);
+	e_dialog_editable_set (priv->organizer, organizer.value);
+
+	cal_component_get_attendee_list (comp, &attendees);
+	for (l = attendees; l != NULL; l = l->next) {
+		CalComponentAttendee *att = l->data;
+		struct attendee *attendee = g_new0 (struct attendee, 1);
+
+		attendee->address = g_strdup (att->value);
+		attendee->member = g_strdup (att->member);
+		attendee->cutype= att->cutype;
+		attendee->role = att->role;
+		attendee->status = att->status;
+		attendee->rsvp = att->rsvp;
+		attendee->delto = g_strdup (att->delto);
+		attendee->delfrom = g_strdup (att->delfrom);
+		attendee->sentby = g_strdup (att->sentby);
+		attendee->cn = g_strdup (att->cn);
+		attendee->language = g_strdup (att->language);
+		
+		priv->attendees = g_slist_prepend (priv->attendees, attendee);
+	
+	}
+	priv->attendees = g_slist_reverse (priv->attendees);
+	cal_component_free_attendee_list (attendees);
 	
-	/* Selector */
-	cal_component_get_dtstart (comp, &dtstart);
-	cal_component_get_dtend (comp, &dtend);
-	start = icaltime_as_zone (*dtstart.value, dtstart.tzid);
-	end = icaltime_as_zone (*dtend.value, dtend.tzid);
-	e_meeting_time_selector_set_meeting_time (priv->selector,
-						  start.year,
-						  start.month,
-						  start.day,
-						  start.hour,
-						  start.minute,
-						  end.year,
-						  end.month,
-						  end.day,
-						  end.hour,
-						  end.minute);
-	cal_component_free_datetime (&dtstart);
-	cal_component_free_datetime (&dtend);
+	/* Table */
+	e_table_model_rows_inserted (priv->model, 0, row_count (priv->model, mpage));
+
+	/* So the comp editor knows we need to send if anything changes */
+	if (priv->attendees != NULL)
+		comp_editor_page_notify_needs_send (COMP_EDITOR_PAGE (mpage));
 
 	priv->updating = FALSE;
 }
@@ -244,66 +316,48 @@ meeting_page_fill_widgets (CompEditorPage *page, CalComponent *comp)
 static void
 meeting_page_fill_component (CompEditorPage *page, CalComponent *comp)
 {
-#if 0
 	MeetingPage *mpage;
 	MeetingPagePrivate *priv;
-	CalComponentDateTime date;
-	time_t t;
-	char *url;
+	CalComponentOrganizer organizer = {NULL, NULL, NULL, NULL};
+	GSList *attendees = NULL, *l;
+	gchar *str;
 	
 	mpage = MEETING_PAGE (page);
 	priv = mpage->priv;
 
-	/* Completed Date. */
-	date.value = g_new (struct icaltimetype, 1);
-	date.tzid = NULL;
-
-	t = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date));
-	if (t != -1) {
-		*date.value = icaltime_from_timet (t, FALSE);
-		cal_component_set_completed (comp, date.value);
-	} else {
-		cal_component_set_completed (comp, NULL);
+	str = e_dialog_editable_get (priv->organizer);
+	if (str == NULL || strlen (str) == 0) {		
+		if (str != NULL)
+			g_free (str);
+		return;
 	}
-
-	g_free (date.value);
-
-	/* URL. */
-	url = e_dialog_editable_get (priv->url);
-	cal_component_set_url (comp, url);
-	if (url)
-		g_free (url);
-#endif
-}
-
-/* set_summary handler for the task page */
-static void
-meeting_page_set_summary (CompEditorPage *page, const char *summary)
-{
-#if 0
-	MeetingPage *mpage;
-	MeetingPagePrivate *priv;
-	gchar *s;
 	
-	mpage = MEETING_PAGE (page);
-	priv = mpage->priv;
-
-	s = e_utf8_to_gtk_string (priv->summary, summary);
-	gtk_label_set_text (GTK_LABEL (priv->summary), s);
-	g_free (s);
-#endif
-}
-
-static void
-meeting_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates)
-{
-	MeetingPage *mpage;
-	MeetingPagePrivate *priv;
-
-	mpage = MEETING_PAGE (page);
-	priv = mpage->priv;
-
-//	comp_editor_date_label (dates, priv->date_time);
+	organizer.value = str;
+	cal_component_set_organizer (comp, &organizer);
+	g_free (str);
+	
+	for (l = priv->attendees; l != NULL; l = l->next) {
+		struct attendee *attendee = l->data;
+		CalComponentAttendee *att = g_new0 (CalComponentAttendee, 1);
+		
+		att->value = attendee->address;
+		att->member = attendee->member;
+		att->cutype= attendee->cutype;
+		att->role = attendee->role;
+		att->status = attendee->status;
+		att->rsvp = attendee->rsvp;
+		att->delto = attendee->delto;
+		att->delfrom = attendee->delfrom;
+		att->sentby = attendee->sentby;
+		att->cn = attendee->cn;
+		att->language = attendee->language;
+		
+		attendees = g_slist_prepend (attendees, att);
+		
+	}
+	attendees = g_slist_reverse (attendees);
+	cal_component_set_attendee_list (comp, attendees);
+	g_slist_free (attendees);
 }
 
 
@@ -323,77 +377,58 @@ get_widgets (MeetingPage *mpage)
 	gtk_widget_ref (priv->main);
 	gtk_widget_unparent (priv->main);
 
-	priv->selector = E_MEETING_TIME_SELECTOR (GW ("selector"));
-	priv->table = GW ("status-table");
+	priv->organizer = GW ("organizer");
+	priv->invite = GW ("invite");
 	
 #undef GW
 
-	return (priv->selector 
-		&& priv->table);
+	return (priv->invite
+		&& priv->organizer);
 }
 
-/* Creates the radio buttons in the given container */
 static void
-create_radio_buttons (GtkWidget *box, GtkWidget **button1, GtkWidget **button2)
+invite_entry_changed (BonoboListener    *listener,
+		      char              *event_name,
+		      CORBA_any         *arg,
+		      CORBA_Environment *ev,
+		      gpointer           user_data)
 {
-	GtkWidget *rb1, *rb2;
-	GSList *grp;
-
-	/* The radio buttions to change views */
-	rb1 = gtk_radio_button_new_with_label (NULL,
-					       "Show attendee scheduling");
-	gtk_widget_show (rb1);
-
-	grp = gtk_radio_button_group (GTK_RADIO_BUTTON (rb1));
-	rb2 = gtk_radio_button_new_with_label (grp, "Show attendee status");
-	gtk_widget_show (rb2);
-	
-	gtk_box_pack_start (GTK_BOX (box), rb1, FALSE, FALSE, 0);
-	gtk_box_pack_start (GTK_BOX (box), rb2, FALSE, FALSE, 0);
-
-	*button1 = rb1;
-	*button2 = rb2;
 }
 
-/* Callback used when the start or end date widgets change.  We check that the
- * start date < end date and we set the "all day task" button as appropriate.
- */
 static void
-date_changed_cb (EDateEdit *dedit, gpointer data)
+add_section (GNOME_Evolution_Addressbook_SelectNames corba_select_names, const char *name)
 {
-#if 0
-	MeetingPage *mpage;
-	MeetingPagePrivate *priv;
-	CompEditorPageDates dates;
+	Bonobo_Control corba_control;
+	CORBA_Environment ev;
+	GtkWidget *control_widget;
+	BonoboControlFrame *cf;
+	Bonobo_PropertyBag pb = CORBA_OBJECT_NIL;
+	CORBA_exception_init (&ev);
 
-	mpage = MEETING_PAGE (data);
-	priv = mpage->priv;
+	GNOME_Evolution_Addressbook_SelectNames_addSection (corba_select_names,
+							    name, name, &ev);
 
-	if (priv->updating)
+	corba_control =
+		GNOME_Evolution_Addressbook_SelectNames_getEntryBySection (
+			corba_select_names, name, &ev);
+
+	if (ev._major != CORBA_NO_EXCEPTION) {
+		CORBA_exception_free (&ev);
 		return;
+	}
 
-	dates.start = 0;
-	dates.end = 0;
-	dates.due = 0;
-	dates.complete = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date));
-	
-	/* Notify upstream */
-	comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (mpage), &dates);
-#endif
-}
+	CORBA_exception_free (&ev);
 
-/* This is called when any field is changed; it notifies upstream. */
-static void
-field_changed_cb (GtkWidget *widget, gpointer data)
-{
-	MeetingPage *mpage;
-	MeetingPagePrivate *priv;
-	
-	mpage = MEETING_PAGE (data);
-	priv = mpage->priv;
-	
-	if (!priv->updating)
-		comp_editor_page_notify_changed (COMP_EDITOR_PAGE (mpage));
+	control_widget = bonobo_widget_new_control_from_objref (
+		corba_control, CORBA_OBJECT_NIL);
+
+	cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_widget));
+	pb = bonobo_control_frame_get_control_property_bag (cf, NULL);
+
+	bonobo_event_source_client_add_listener (
+		pb, invite_entry_changed,
+		"Bonobo/Property:change:entry_changed",
+		NULL, NULL);
 }
 
 static gboolean
@@ -411,6 +446,10 @@ get_select_name_dialog (MeetingPage *mpage)
 
 	priv->corba_select_names = oaf_activate_from_id (SELECT_NAMES_OAFID, 0, NULL, &ev);
 
+	add_section (priv->corba_select_names, "Required Participants");
+	add_section (priv->corba_select_names, "Optional Participants");
+	add_section (priv->corba_select_names, "Non-Participants");
+
 	/* OAF seems to be broken -- it can return a CORBA_OBJECT_NIL without
            raising an exception in `ev'.  */
 	if (ev._major != CORBA_NO_EXCEPTION || priv->corba_select_names == CORBA_OBJECT_NIL) {
@@ -424,6 +463,20 @@ get_select_name_dialog (MeetingPage *mpage)
 	return TRUE;
 }
 
+/* This is called when any field is changed; it notifies upstream. */
+static void
+field_changed_cb (GtkWidget *widget, gpointer data)
+{
+	MeetingPage *mpage;
+	MeetingPagePrivate *priv;
+	
+	mpage = MEETING_PAGE (data);
+	priv = mpage->priv;
+	
+	if (!priv->updating)
+		comp_editor_page_notify_changed (COMP_EDITOR_PAGE (mpage));
+}
+
 /* Function called to invite more people */
 static void
 invite_cb (GtkWidget *widget, gpointer data) 
@@ -440,64 +493,363 @@ invite_cb (GtkWidget *widget, gpointer data)
 	
 	CORBA_exception_init (&ev);
 
-	GNOME_Evolution_Addressbook_SelectNames_addSection (
-		priv->corba_select_names, "Required", "Required", &ev);
-
 	GNOME_Evolution_Addressbook_SelectNames_activateDialog (
-		priv->corba_select_names, "Test", &ev);
+		priv->corba_select_names, "Required Participants", &ev);
 
 	CORBA_exception_free (&ev);
-
-	if (!priv->updating)
-		comp_editor_page_notify_changed (COMP_EDITOR_PAGE (mpage));
 }
 
+/* Hooks the widget signals */
 static void
-page_toggle_cb (GtkWidget *widget, gpointer data)
+init_widgets (MeetingPage *mpage)
 {
+	MeetingPagePrivate *priv;
+
+	priv = mpage->priv;
+
+	/* Organizer */
+	gtk_signal_connect (GTK_OBJECT (priv->organizer), "changed",
+			    GTK_SIGNAL_FUNC (field_changed_cb), mpage);
+
+	/* Invite button */
+	gtk_signal_connect (GTK_OBJECT (priv->invite), "clicked", 
+			    GTK_SIGNAL_FUNC (invite_cb), mpage);
+}
+
+static CalComponentRole
+text_to_role (const char *role)
+{
+	if (!g_strcasecmp (role, "Chair"))
+		return CAL_COMPONENT_ROLE_CHAIR;
+	else if (!g_strcasecmp (role, "Required Participant"))
+		return CAL_COMPONENT_ROLE_REQUIRED;
+	else if (!g_strcasecmp (role, "Optional Participant"))
+		return CAL_COMPONENT_ROLE_OPTIONAL;
+	else if (!g_strcasecmp (role, "Non-Participant"))
+		return CAL_COMPONENT_ROLE_NON;
+	else
+		return CAL_COMPONENT_ROLE_UNKNOWN;
+}
+
+static char *
+role_to_text (CalComponentRole role) 
+{
+	switch (role) {
+	case CAL_COMPONENT_ROLE_CHAIR:
+		return "Chair";
+	case CAL_COMPONENT_ROLE_REQUIRED:
+		return "Required Participant";
+	case CAL_COMPONENT_ROLE_OPTIONAL:
+		return "Optional Participant";
+	case CAL_COMPONENT_ROLE_NON:
+		return "Non-Participant";
+	default:
+		return "Unknown";
+	}
+
+	return NULL;
+}
+
+static gboolean
+text_to_boolean (const char *role)
+{
+	if (!g_strcasecmp (role, "Yes"))
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static char *
+boolean_to_text (gboolean b) 
+{
+	if (b)
+		return "Yes";
+	else
+		return "No";
+}
+
+static CalComponentPartStat
+text_to_partstat (const char *partstat)
+{
+	if (!g_strcasecmp (partstat, "Needs Action"))
+		return CAL_COMPONENT_PARTSTAT_NEEDSACTION;
+	else if (!g_strcasecmp (partstat, "Accepted"))
+		return CAL_COMPONENT_PARTSTAT_ACCEPTED;
+	else if (!g_strcasecmp (partstat, "Declined"))
+		return CAL_COMPONENT_PARTSTAT_DECLINED;
+	else if (!g_strcasecmp (partstat, "Tentative"))
+		return CAL_COMPONENT_PARTSTAT_TENTATIVE;
+	else if (!g_strcasecmp (partstat, "Delegated"))
+		return CAL_COMPONENT_PARTSTAT_DELEGATED;
+	else if (!g_strcasecmp (partstat, "Completed"))
+		return CAL_COMPONENT_PARTSTAT_COMPLETED;
+	else if (!g_strcasecmp (partstat, "In Process"))
+		return CAL_COMPONENT_PARTSTAT_INPROCESS;
+	else
+		return CAL_COMPONENT_PARTSTAT_UNKNOWN;
+}
+
+static char *
+partstat_to_text (CalComponentPartStat partstat) 
+{
+	switch (partstat) {
+	case CAL_COMPONENT_PARTSTAT_NEEDSACTION:
+		return "Needs Action";
+	case CAL_COMPONENT_PARTSTAT_ACCEPTED:
+		return "Accepted";
+	case CAL_COMPONENT_PARTSTAT_DECLINED:
+		return "Declined";
+	case CAL_COMPONENT_PARTSTAT_TENTATIVE:
+		return "Tentative";
+	case CAL_COMPONENT_PARTSTAT_DELEGATED:
+		return "Delegated";
+	case CAL_COMPONENT_PARTSTAT_COMPLETED:
+		return "Completed";
+	case CAL_COMPONENT_PARTSTAT_INPROCESS:
+		return "In Process";
+	case CAL_COMPONENT_PARTSTAT_UNKNOWN:
+	default:
+		return "Unknown";
+	}
+
+	return NULL;
+}
+
+static int
+column_count (ETableModel *etm, void *data)
+{
+	return MEETING_COLUMN_COUNT;
+}
+
+static int
+row_count (ETableModel *etm, void *data)
+{
+	MeetingPage *mpage;
+	MeetingPagePrivate *priv;
+
+	mpage = MEETING_PAGE (data);	
+	priv = mpage->priv;
+
+	return g_slist_length (priv->attendees);
+}
+
+static void
+append_row (ETableModel *etm, ETableModel *model, int row, void *data)
+{	
 	MeetingPage *mpage;
 	MeetingPagePrivate *priv;
-	gboolean active;
+	struct attendee *attendee;
+	gint row_cnt;
 	
-	mpage = MEETING_PAGE (data);
+	mpage = MEETING_PAGE (data);	
 	priv = mpage->priv;
 
-	active = GTK_TOGGLE_BUTTON (widget)->active;
-	if (active)
-		gtk_notebook_set_page (GTK_NOTEBOOK (priv->main), 0);
-	else
-		gtk_notebook_set_page (GTK_NOTEBOOK (priv->main), 1);
+	attendee = g_new0 (struct attendee, 1);
+	
+	attendee->address = g_strdup (e_table_model_value_at (model, MEETING_ATTENDEE_COL, row));
+	attendee->role = text_to_role (e_table_model_value_at (model, MEETING_ROLE_COL, row));
+	attendee->rsvp = text_to_boolean (e_table_model_value_at (model, MEETING_RSVP_COL, row));
+	attendee->status = text_to_partstat (e_table_model_value_at (model, MEETING_STATUS_COL, row));
+
+	priv->attendees = g_slist_append (priv->attendees, attendee);
+	
+	row_cnt = row_count (etm, data) - 1;
+	e_table_model_row_inserted (E_TABLE_MODEL (etm), row_cnt);
 
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rb1[0]), active);
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rb1[1]), !active);
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rb2[0]), active);
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->rb2[1]), !active);
+	comp_editor_page_notify_needs_send (COMP_EDITOR_PAGE (mpage));
+	comp_editor_page_notify_changed (COMP_EDITOR_PAGE (mpage));
 }
+
+static void *
+value_at (ETableModel *etm, int col, int row, void *data)
+{
+	MeetingPage *mpage;
+	MeetingPagePrivate *priv;
+	struct attendee *attendee;
+
+	mpage = MEETING_PAGE (data);	
+	priv = mpage->priv;
+
+	attendee = g_slist_nth_data (priv->attendees, row);
 	
-/* Hooks the widget signals */
+	switch (col) {
+	case MEETING_ATTENDEE_COL:
+		return attendee->address;
+	case MEETING_ROLE_COL:
+		return role_to_text (attendee->role);
+	case MEETING_RSVP_COL:
+		return boolean_to_text (attendee->rsvp);
+	case MEETING_STATUS_COL:
+		return partstat_to_text (attendee->status);
+	}
+	
+	return NULL;
+}
+
 static void
-init_widgets (MeetingPage *mpage)
+set_value_at (ETableModel *etm, int col, int row, const void *val, void *data)
 {
+	MeetingPage *mpage;
 	MeetingPagePrivate *priv;
+	struct attendee *attendee;
 
+	mpage = MEETING_PAGE (data);	
 	priv = mpage->priv;
+	
+	attendee = g_slist_nth_data (priv->attendees, row);
+	
+	switch (col) {
+	case MEETING_ATTENDEE_COL:
+		attendee->address = g_strdup (val);
+		break;
+	case MEETING_ROLE_COL:
+		attendee->role = text_to_role (val);
+		break;
+	case MEETING_RSVP_COL:
+		attendee->rsvp = text_to_boolean (val);
+		break;
+	case MEETING_STATUS_COL:
+		attendee->status = text_to_partstat (val);
+		break;
+	}
+
+	if (!priv->updating) {		
+		comp_editor_page_notify_needs_send (COMP_EDITOR_PAGE (mpage));
+		comp_editor_page_notify_changed (COMP_EDITOR_PAGE (mpage));
+	}
+}
 
-	/* Selector */
-	gtk_signal_connect (GTK_OBJECT (priv->selector->invite_button), 
-			    "clicked", GTK_SIGNAL_FUNC (invite_cb), mpage);
+static gboolean
+is_cell_editable (ETableModel *etm, int col, int row, void *data)
+{
+	return TRUE;
+}
 
-	/* Radio buttons */
-	gtk_signal_connect (GTK_OBJECT (priv->rb1[0]), "toggled", 
-			    GTK_SIGNAL_FUNC (page_toggle_cb), mpage);
-	gtk_signal_connect (GTK_OBJECT (priv->rb2[0]), "toggled", 
-			    GTK_SIGNAL_FUNC (page_toggle_cb), mpage);
+static void *
+duplicate_value (ETableModel *etm, int col, const void *val, void *data)
+{
+	return g_strdup (val);
+}
+
+static void
+free_value (ETableModel *etm, int col, void *val, void *data)
+{
+	g_free (val);
+}
+
+static void *
+init_value (ETableModel *etm, int col, void *data)
+{
+	switch (col) {
+	case MEETING_ATTENDEE_COL:
+		return g_strdup ("");
+	case MEETING_ROLE_COL:
+		return g_strdup ("Required Participant");
+	case MEETING_RSVP_COL:
+		return g_strdup ("Yes");
+	case MEETING_STATUS_COL:
+		return g_strdup ("Needs Action");
+	}
 	
-#if 0
-	/* Completed Date */
-	gtk_signal_connect (GTK_OBJECT (priv->completed_date), "changed",
-			    GTK_SIGNAL_FUNC (date_changed_cb), mpage);
+	return g_strdup ("");
+}
 
-#endif
+static gboolean
+value_is_empty (ETableModel *etm, int col, const void *val, void *data)
+{
+	if (col == 0) {
+		if (val && !g_strcasecmp (val, ""))
+			return TRUE;
+		else
+			return FALSE;
+	}
+	
+	return TRUE;
+}
+
+static char *
+value_to_string (ETableModel *etm, int col, const void *val, void *data)
+{
+	return g_strdup (val);
+}
+
+static void
+build_etable (MeetingPage *mpage)
+{
+	MeetingPagePrivate *priv;
+	ETableExtras *extras;
+	GList *strings;
+	ECell *popup_cell, *cell;
+	
+	priv = mpage->priv;
+	
+	extras = e_table_extras_new ();
+	
+	/* For role */
+	cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+	popup_cell = e_cell_combo_new ();
+	e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell);
+	gtk_object_unref (GTK_OBJECT (cell));
+	
+	strings = NULL;
+	strings = g_list_append (strings, "Chair");
+	strings = g_list_append (strings, "Required Participant");
+	strings = g_list_append (strings, "Optional Participant");
+	strings = g_list_append (strings, "Non-Participant");
+	strings = g_list_append (strings, "Unknown");
+
+	e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings);
+	e_table_extras_add_cell (extras, "roleedit", popup_cell);
+
+	/* For rsvp */
+	cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+	popup_cell = e_cell_combo_new ();
+	e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell);
+	gtk_object_unref (GTK_OBJECT (cell));
+
+	strings = NULL;
+	strings = g_list_append (strings, "Yes");
+	strings = g_list_append (strings, "No");
+
+	e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings);
+	e_table_extras_add_cell (extras, "rsvpedit", popup_cell);
+
+	/* For status */
+	cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+	popup_cell = e_cell_combo_new ();
+	e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell);
+	gtk_object_unref (GTK_OBJECT (cell));
+
+	strings = NULL;
+	strings = g_list_append (strings, "Needs Action");
+	strings = g_list_append (strings, "Accepted");
+	strings = g_list_append (strings, "Declined");
+	strings = g_list_append (strings, "Tentative");
+	strings = g_list_append (strings, "Delegated");
+
+	e_cell_combo_set_popdown_strings (E_CELL_COMBO (popup_cell), strings);
+	e_table_extras_add_cell (extras, "statusedit", popup_cell);
+
+
+	/* The table itself */
+	priv->model = e_table_simple_new (column_count,
+					  row_count,
+					  value_at,
+					  set_value_at,
+					  is_cell_editable,
+					  duplicate_value,
+					  free_value,
+					  init_value,
+					  value_is_empty,
+					  value_to_string,
+					  mpage);
+	gtk_object_set (GTK_OBJECT (priv->model),
+			"append_row", append_row,
+			NULL);
+	
+	priv->etable = e_table_scrolled_new (priv->model, extras, 
+					     MEETING_PAGE_TABLE_SPEC, NULL);
+	gtk_object_unref (GTK_OBJECT (extras));
 }
 
 
@@ -515,7 +867,6 @@ MeetingPage *
 meeting_page_construct (MeetingPage *mpage)
 {
 	MeetingPagePrivate *priv;
-	GtkWidget *vbox;
 	
 	priv = mpage->priv;
 
@@ -532,20 +883,12 @@ meeting_page_construct (MeetingPage *mpage)
 			   "Could not find all widgets in the XML file!");
 		return NULL;
 	}
-
-	/* Stuff for the second page */
-	vbox = gtk_vbox_new (FALSE, 2);
-	gtk_widget_show (vbox);
-	gtk_table_attach (GTK_TABLE (priv->table), vbox, 0, 1, 0, 1,
-			  GTK_EXPAND | GTK_FILL, GTK_FILL, 2, 0);
-
-	/* The radio buttions to change views on first page */
-	create_radio_buttons (priv->selector->attendees_title_bar_vbox, 
-			      &priv->rb1[0], &priv->rb1[1]);
-
-	/* The radio buttions to change views on second page */
-	create_radio_buttons (vbox, &priv->rb2[0], &priv->rb2[1]);
-
+	
+	/* The etable displaying attendees and their status */
+	build_etable (mpage);	
+	gtk_widget_show (priv->etable);
+	gtk_box_pack_start (GTK_BOX (priv->main), priv->etable, TRUE, TRUE, 2);
+	
 	/* Init the widget signals */
 	init_widgets (mpage);
 
@@ -573,15 +916,3 @@ meeting_page_new (void)
 
 	return mpage;
 }
-
-GtkWidget *meeting_page_create_selector (void);
-
-GtkWidget *
-meeting_page_create_selector (void)
-{
-	GtkWidget *sel;
-
-	sel = e_meeting_time_selector_new ();
-
-	return sel;
-}
diff --git a/calendar/gui/dialogs/meeting-page.glade b/calendar/gui/dialogs/meeting-page.glade
index 86e6647b93..4e23c16f67 100644
--- a/calendar/gui/dialogs/meeting-page.glade
+++ b/calendar/gui/dialogs/meeting-page.glade
@@ -25,60 +25,75 @@
   <auto_shrink>False</auto_shrink>
 
   <widget>
-    <class>GtkNotebook</class>
+    <class>GtkVBox</class>
     <name>meeting-page</name>
-    <show_tabs>False</show_tabs>
-    <show_border>False</show_border>
-    <tab_pos>GTK_POS_TOP</tab_pos>
-    <scrollable>False</scrollable>
-    <tab_hborder>2</tab_hborder>
-    <tab_vborder>2</tab_vborder>
-    <popup_enable>False</popup_enable>
+    <border_width>5</border_width>
+    <homogeneous>False</homogeneous>
+    <spacing>4</spacing>
 
     <widget>
-      <class>Custom</class>
-      <name>selector</name>
-      <creation_function>meeting_page_create_selector</creation_function>
-      <int1>0</int1>
-      <int2>0</int2>
-      <last_modification_time>Mon, 04 Jun 2001 17:53:38 GMT</last_modification_time>
-    </widget>
+      <class>GtkHBox</class>
+      <name>hbox1</name>
+      <homogeneous>False</homogeneous>
+      <spacing>4</spacing>
+      <child>
+	<padding>0</padding>
+	<expand>False</expand>
+	<fill>False</fill>
+      </child>
 
-    <widget>
-      <class>GtkLabel</class>
-      <child_name>Notebook:tab</child_name>
-      <name>label1</name>
-      <label>label1</label>
-      <justify>GTK_JUSTIFY_CENTER</justify>
-      <wrap>False</wrap>
-      <xalign>0.5</xalign>
-      <yalign>0.5</yalign>
-      <xpad>0</xpad>
-      <ypad>0</ypad>
+      <widget>
+	<class>GtkLabel</class>
+	<name>label1</name>
+	<label>Organizer</label>
+	<justify>GTK_JUSTIFY_CENTER</justify>
+	<wrap>False</wrap>
+	<xalign>0.5</xalign>
+	<yalign>0.5</yalign>
+	<xpad>0</xpad>
+	<ypad>0</ypad>
+	<child>
+	  <padding>0</padding>
+	  <expand>False</expand>
+	  <fill>False</fill>
+	</child>
+      </widget>
+
+      <widget>
+	<class>GtkEntry</class>
+	<name>organizer</name>
+	<can_focus>True</can_focus>
+	<editable>True</editable>
+	<text_visible>True</text_visible>
+	<text_max_length>0</text_max_length>
+	<text></text>
+	<child>
+	  <padding>0</padding>
+	  <expand>True</expand>
+	  <fill>True</fill>
+	</child>
+      </widget>
+
+      <widget>
+	<class>Placeholder</class>
+      </widget>
     </widget>
 
     <widget>
-      <class>GtkTable</class>
-      <name>status-table</name>
-      <border_width>2</border_width>
-      <rows>2</rows>
-      <columns>2</columns>
-      <homogeneous>False</homogeneous>
-      <row_spacing>0</row_spacing>
-      <column_spacing>0</column_spacing>
+      <class>Placeholder</class>
     </widget>
 
     <widget>
-      <class>GtkLabel</class>
-      <child_name>Notebook:tab</child_name>
-      <name>label2</name>
-      <label>label2</label>
-      <justify>GTK_JUSTIFY_CENTER</justify>
-      <wrap>False</wrap>
-      <xalign>0.5</xalign>
-      <yalign>0.5</yalign>
-      <xpad>0</xpad>
-      <ypad>0</ypad>
+      <class>GtkButton</class>
+      <name>invite</name>
+      <can_focus>True</can_focus>
+      <label>Invite Others</label>
+      <child>
+	<padding>0</padding>
+	<expand>False</expand>
+	<fill>False</fill>
+	<pack>GTK_PACK_END</pack>
+      </child>
     </widget>
   </widget>
 </widget>
diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c
index 77b22a97ac..c5c45def15 100644
--- a/calendar/gui/dialogs/recurrence-page.c
+++ b/calendar/gui/dialogs/recurrence-page.c
@@ -1726,10 +1726,12 @@ recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates)
 	priv->weekday_day_mask = priv->weekday_day_mask | mask;
 	priv->weekday_blocked_day_mask = mask;
 
-	weekday_picker_set_days (priv->weekday_picker,
-				 priv->weekday_day_mask);
-	weekday_picker_set_blocked_days (priv->weekday_picker,
-					 priv->weekday_blocked_day_mask);
+	if (priv->weekday_picker != NULL) {
+		weekday_picker_set_days (WEEKDAY_PICKER (priv->weekday_picker),
+					 priv->weekday_day_mask);
+		weekday_picker_set_blocked_days (WEEKDAY_PICKER (priv->weekday_picker),
+						 priv->weekday_blocked_day_mask);
+	}
 }
 
 
diff --git a/calendar/gui/dialogs/send-comp.c b/calendar/gui/dialogs/send-comp.c
new file mode 100644
index 0000000000..8b1824866c
--- /dev/null
+++ b/calendar/gui/dialogs/send-comp.c
@@ -0,0 +1,84 @@
+/* Evolution calendar - Send calendar component dialog
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Author: JP Rosevear <jpr@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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-uidefs.h>
+#include <gal/widgets/e-unicode.h>
+#include "send-comp.h"
+
+
+
+/**
+ * send_component_dialog:
+ * 
+ * Pops up a dialog box asking the user whether he wants to send a
+ * iTip/iMip message
+ * 
+ * Return value: TRUE if the user clicked Yes, FALSE otherwise.
+ **/
+gboolean
+send_component_dialog (CalComponent *comp)
+{
+	GtkWidget *dialog;
+	CalComponentVType vtype;
+	char *str;
+
+	str = _("The meeting status has changed. Send an updated version?");
+
+	vtype = cal_component_get_vtype (comp);
+
+	switch (vtype) {
+	case CAL_COMPONENT_EVENT:
+		str = g_strdup_printf (_("The meeting information has changed. "
+					 "Send an updated version?"));
+		break;
+
+	case CAL_COMPONENT_TODO:
+		str = g_strdup_printf (_("The task information has changed. "
+					 "Send an updated version?"));
+		break;
+
+	case CAL_COMPONENT_JOURNAL:
+		str = g_strdup_printf (_("The journal entry has changed. "
+					 "Send an updated version?"));
+		break;
+
+	default:
+		g_message ("send_component_dialog(): "
+			   "Cannot handle object of type %d", vtype);
+		return FALSE;
+	}
+	
+	dialog = gnome_question_dialog_modal (str, NULL, NULL);
+
+	if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_YES)
+		return TRUE;
+	else
+		return FALSE;
+}
diff --git a/calendar/gui/dialogs/send-comp.h b/calendar/gui/dialogs/send-comp.h
new file mode 100644
index 0000000000..f60ab947aa
--- /dev/null
+++ b/calendar/gui/dialogs/send-comp.h
@@ -0,0 +1,30 @@
+/* Evolution calendar - Send calendar component dialog
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Author: JP Rosevear <jpr@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.
+ */
+
+#ifndef SEND_COMP_H
+#define SEND_COMP_H
+
+#include <glib.h>
+#include <cal-util/cal-component.h>
+
+gboolean send_component_dialog (CalComponent *comp);
+
+#endif
-- 
cgit v1.2.3