[evolution-patches] Bug 200821: Memos/Notes component implementation



This is a patch for Bug 200821: implementation of a Memos/Notes component
(http://bugzilla.gnome.org/show_bug.cgi?id=200821). The patches are for
evoultion and the evolution data server. These patches include the changes
suggested on evolution-hackers. It also includes additions to various ChangeLog
files. The patches are based on CVs as of the night of Monday, July 25.

This is an initial implementation. There are no doubt bugs, but hopefully with
enough people using it, we can get them worked out. I plan to spend a good
amount of time working on maintaining and improving the code, since it is such
a large edition to the Evolution code base.

Let me know what you think.

Thanks,
Nathan Owens


		
____________________________________________________
Start your day with Yahoo! - make it your home page 
http://www.yahoo.com/r/hs 
 
Index: calendar/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/ChangeLog,v
retrieving revision 1.485
diff -u -r1.485 ChangeLog
--- calendar/ChangeLog	25 Jul 2005 04:58:29 -0000	1.485
+++ calendar/ChangeLog	26 Jul 2005 02:31:41 -0000
@@ -1,3 +1,10 @@
+2005-07-25  Nathan Owens <pianocomp81 yahoo com>
+	
+	* libecal/e-cal.c: (e_cal_new_system_memos): added backend
+	support for Memos component. Finished implement VJOURNAL support
+	* libecal/e-cal.h: (e_cal_new_system_memos): added prototype
+	* tests/ecal/test-ecal.c: (test_new_system_memos): added memos test
+
 2005-07-23  Chenthill Palanisamy  <pchenthill novell com>
 
 	* backends/groupwise/e-cal-backend-groupwise-utils.c:
Index: calendar/libecal/e-cal.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libecal/e-cal.c,v
retrieving revision 1.108
diff -u -r1.108 e-cal.c
--- calendar/libecal/e-cal.c	11 Jul 2005 02:19:28 -0000	1.108
+++ calendar/libecal/e-cal.c	26 Jul 2005 02:31:46 -0000
@@ -1527,6 +1527,19 @@
 	return ecal;
 }
 
+ECal *
+e_cal_new_system_memos (void)
+{
+	ECal *ecal;
+	char *uri;
+
+	uri = g_build_filename ("file://", g_get_home_dir (), ".evolution", "memos", "local", "system", NULL);
+	ecal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
+	g_free (uri);
+	
+	return ecal;
+}
+
 /**
  * e_cal_set_auth_func
  * @ecal: A calendar client.
@@ -2830,7 +2843,8 @@
 		} else {
 			kind = icalcomponent_isa (tmp_icalcomp);
 			if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
-			    (kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO)) {
+			    (kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO) ||
+			    (kind == ICAL_VJOURNAL_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_JOURNAL)) {
 				*icalcomp = icalcomponent_new_clone (tmp_icalcomp);
 			} else if (kind == ICAL_VCALENDAR_COMPONENT) {
 				icalcomponent *subcomp = NULL;
@@ -5254,6 +5268,9 @@
 	case E_CAL_SOURCE_TYPE_TODO:
 		return get_sources (sources, "/apps/evolution/tasks/sources", error);
 		break;
+	case E_CAL_SOURCE_TYPE_JOURNAL:
+		return get_sources (sources, "/apps/evolution/memos/sources", error);
+		break;
 	default:
 		/* FIXME Fill in error */
 		return FALSE;
Index: calendar/libecal/e-cal.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libecal/e-cal.h,v
retrieving revision 1.25
diff -u -r1.25 e-cal.h
--- calendar/libecal/e-cal.h	11 Jul 2005 00:51:07 -0000	1.25
+++ calendar/libecal/e-cal.h	26 Jul 2005 02:31:46 -0000
@@ -104,6 +104,7 @@
 ECal *e_cal_new_from_uri (const gchar *uri, ECalSourceType type);
 ECal *e_cal_new_system_calendar (void);
 ECal *e_cal_new_system_tasks (void);
+ECal *e_cal_new_system_memos (void);
 
 void e_cal_set_auth_func (ECal *ecal, ECalAuthFunc func, gpointer data);
 
Index: calendar/tests/ecal/test-ecal.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/tests/ecal/test-ecal.c,v
retrieving revision 1.4
diff -u -r1.4 test-ecal.c
--- calendar/tests/ecal/test-ecal.c	2 Feb 2005 18:44:32 -0000	1.4
+++ calendar/tests/ecal/test-ecal.c	26 Jul 2005 02:31:48 -0000
@@ -475,6 +475,23 @@
 }
 
 static char *
+test_new_system_memos()
+{
+	ECal *cal;
+	char *uri;
+	gboolean created;
+	
+	cal = e_cal_new_system_memos ();
+	uri = g_build_filename (g_get_home_dir (), ".evolution", "memos", "local", "system", "journal.ics", NULL);
+	created = g_file_test (uri, G_FILE_TEST_EXISTS);
+	g_free (uri);
+	
+	mu_assert ("Test creation of default system memos : Failed", created);
+	
+	return NULL;
+}
+
+static char *
 test_get_free_busy (ECal *client)
 {
 	// TODO uses NULL for users and currently specific to file backend.
@@ -608,6 +625,7 @@
 		
 	mu_run_test (test_new_system_calendar ());
 	mu_run_test (test_new_system_tasks ());
+	mu_run_test (test_new_system_memos ());
 	mu_run_test (test_set_uri (client, uri));
 	mu_run_test (test_get_source (client, uri));
 	mu_run_test (test_cal_loaded (client));
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/ChangeLog,v
retrieving revision 1.1509
diff -u -r1.1509 ChangeLog
--- ChangeLog	20 Jul 2005 08:19:50 -0000	1.1509
+++ ChangeLog	26 Jul 2005 03:36:13 -0000
@@ -1,3 +1,7 @@
+2005-07-25  Nathan Owens <pianocomp81 yahoo com>
+	* configure.in: Add views/memos/Makefile,
+	calendar/conduits/memo/Makefile to Makefile list
+
 2005-07-20  Tor Lillqvist  <tml novell com>
 
 	* configure.in: Add AC_LIBTOOL_WIN32_DLL. It is apparently
Index: configure.in
===================================================================
RCS file: /cvs/gnome/evolution/configure.in,v
retrieving revision 1.837
diff -u -r1.837 configure.in
--- configure.in	20 Jul 2005 08:19:50 -0000	1.837
+++ configure.in	26 Jul 2005 03:36:14 -0000
@@ -1640,6 +1640,7 @@
 views/calendar/Makefile
 views/mail/Makefile
 views/tasks/Makefile
+views/memos/Makefile
 widgets/Makefile
 widgets/e-timezone-dialog/Makefile
 widgets/menus/Makefile
@@ -1653,6 +1654,7 @@
 calendar/conduits/Makefile
 calendar/conduits/todo/Makefile
 calendar/conduits/calendar/Makefile
+calendar/conduits/memo/Makefile
 calendar/gui/Makefile
 calendar/gui/alarm-notify/Makefile
 calendar/gui/dialogs/Makefile
Index: calendar/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/calendar/ChangeLog,v
retrieving revision 1.2779
diff -u -r1.2779 ChangeLog
--- calendar/ChangeLog	25 Jul 2005 07:53:17 -0000	1.2779
+++ calendar/ChangeLog	26 Jul 2005 03:36:24 -0000
@@ -1,3 +1,36 @@
+2005-07-25  Nathan Owens <pianocomp81 yahoo com
+	* calendar.error.xml: Added strings for memos
+	* calendar/conduits/Makefile.am: added 'memo' to SUBDIRS
+	* calendar/conduits/memo/*: initial memo conduit
+	* calendar/gui/calendar-config.[ch]: (calendar_config_get_memos_selected)
+	(calendar_config_set_memos_selected) (calendar_config_add_notification_memos_selected): 
+	gconf get/set for memos lists
+	* calendar/gui/calendar-config-keys.h: added gconf keys for Memos component
+	* calendar/gui/comp-util.[ch] (cal_comp_memo_new_with_defaults): added function
+	to create memo component with defaults
+	* calendar/gui/e-cal-component-memo-preview.[ch]: initial file for preview of a memo
+	* calendar/gui/e-cal-model-memos.[ch]: initial model for the memos component.
+	* calendar/gui/e-memos.[ch]: initial memos base
+	* calendar/gui/e-memo-table.[ch]: initial view for memos component
+	* calendar/gui/e-memo-table.etspec: etspec for memos e-table
+	* calendar/gui/e-memo-table-config.[ch]: initial configuration for memos e-table view
+	* calendar/gui/GNOME_Evolution_Calendar.server.in.in: added Memos component
+	* calendar/gui/main.c: added initialization code for Memos component
+	* calendar/gui/Makefile.am: added entries for new files for Memos component
+	* calendar/gui/memos-component.[ch]: Memos component base code
+	* calendar/gui/memos-control.[ch]: initial user control code. Used for printing,
+	copying, etc.
+	* calendar/gui/migration.c: added migration for memos component - also takes care
+	of initialization for the first time the Memos component is run.
+	* calendar/gui/dialogs/calendar-setup.[ch]: added code to create a new Memo List
+	* calendar/gui/dialogs/Makefile.am: added files for build
+	* calendar/gui/dialogs/memo-editor.[ch]: initial memo editor
+	* calendar/gui/dialogs/memo-page.[ch]: page in editor for editing a memo
+	* calendar/gui/dialogs/memo-page.glade: glade file for memo-editor-page
+	* calendar/gui/dialogs/send-comp.c: added E_CAL_COMPONENT_JOURNAL support for Memo
+	component
+
+
 2005-07-25  Viren.l  <lviren novel com>
 
 	Fixes:248126
Index: calendar/calendar.error.xml
===================================================================
RCS file: /cvs/gnome/evolution/calendar/calendar.error.xml,v
retrieving revision 1.3
diff -u -r1.3 calendar.error.xml
--- calendar/calendar.error.xml	6 Jul 2005 07:14:57 -0000	1.3
+++ calendar/calendar.error.xml	26 Jul 2005 03:36:24 -0000
@@ -194,6 +194,13 @@
   <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
   <button stock="gtk-delete" response="GTK_RESPONSE_YES"/>
  </error>
+
+ <error id="prompt-delete-memo-list" type="question" modal="true" default="GTK_RESPONSE_CANCEL">
+  <_primary>Delete memo list '{0}'?</_primary>
+  <_secondary>This memo list will be removed permanently.</_secondary>
+  <button stock="gtk-cancel" response="GTK_RESPONSE_NO"/>
+  <button stock="gtk-delete" response="GTK_RESPONSE_YES"/>
+ </error>
  
  <error id="prompt-send-no-subject-calendar" type="question" default="GTK_RESPONSE_YES">
   <_primary>Are you sure you want to send the appointment without a summary?</_primary>
@@ -221,6 +228,12 @@
   <button stock ="gtk-ok" response="GTK_RESPONSE_YES"/>
  </error>
 
+ <error id="prompt-no-contents-offline-memos" type="error" default="GTK_RESPONSE_YES">
+  <_primary>Error loading memo list</_primary>
+  <_secondary>The memo list is not marked for offline usage</_secondary>
+  <button stock ="gtk-ok" response="GTK_RESPONSE_YES"/>
+ </error>
+
  <error id="server-version" type="warning">
  <title>Server Version</title> 
  <_primary>Some features may not work properly with your current server</_primary>
Index: calendar/conduits/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/calendar/conduits/Makefile.am,v
retrieving revision 1.2
diff -u -r1.2 Makefile.am
--- calendar/conduits/Makefile.am	12 Jul 2000 23:34:10 -0000	1.2
+++ calendar/conduits/Makefile.am	26 Jul 2005 03:36:24 -0000
@@ -1 +1 @@
-SUBDIRS = calendar todo
+SUBDIRS = calendar memo todo
Index: calendar/gui/GNOME_Evolution_Calendar.server.in.in
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/GNOME_Evolution_Calendar.server.in.in,v
retrieving revision 1.17
diff -u -r1.17 GNOME_Evolution_Calendar.server.in.in
--- calendar/gui/GNOME_Evolution_Calendar.server.in.in	18 Jun 2005 11:31:51 -0000	1.17
+++ calendar/gui/GNOME_Evolution_Calendar.server.in.in	26 Jul 2005 03:36:24 -0000
@@ -71,6 +71,26 @@
 	<oaf_attribute name="evolution:button_sort_order" type="string" value="-8"/>
 </oaf_server>
 
+<oaf_server iid="OAFIID:GNOME_Evolution_Memos_Component:@VERSION@"
+            type="factory"
+            location="OAFIID:GNOME_Evolution_Calendar_Factory:@VERSION@">
+
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:GNOME/Evolution/Component:@VERSION@"/>
+	</oaf_attribute>
+
+	<oaf_attribute name="evolution:component_alias" type="string" value="memos"/>
+
+	<oaf_attribute name="name" type="string" _value="Evolution's Memos component"/>
+
+	<oaf_attribute name="evolution:menu_label" type="string" _value="Memo_s"/>
+	<oaf_attribute name="evolution:menu_accelerator" type="string" value="*Control*F6"/>
+	<oaf_attribute name="evolution:button_label" type="string" _value="Memos"/>
+	<oaf_attribute name="evolution:button_tooltips" type="string" _value="Memos"/>
+        <oaf_attribute name="evolution:button_icon" type="string" value="stock_notes"/>
+	<oaf_attribute name="evolution:button_sort_order" type="string" value="-8"/>
+</oaf_server>
+
 <oaf_server iid="OAFIID:GNOME_Evolution_Calendar_CompEditorFactory:@VERSION@"
             type="factory"
             location="OAFIID:GNOME_Evolution_Calendar_Factory:@VERSION@">
Index: calendar/gui/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/Makefile.am,v
retrieving revision 1.305
diff -u -r1.305 Makefile.am
--- calendar/gui/Makefile.am	12 Jul 2005 04:04:10 -0000	1.305
+++ calendar/gui/Makefile.am	26 Jul 2005 03:36:24 -0000
@@ -75,7 +75,8 @@
 etspec_DATA =				\
 	e-calendar-table.etspec		\
 	e-meeting-time-sel.etspec	\
-	e-cal-list-view.etspec
+	e-cal-list-view.etspec		\
+	e-memo-table.etspec
 
 libevolution_calendar_la_SOURCES =		\
 	$(IDL_GENERATED)			\
@@ -105,6 +106,8 @@
 	e-alarm-list.h				\
 	e-cal-component-preview.c		\
 	e-cal-component-preview.h		\
+	e-cal-component-memo-preview.c		\
+	e-cal-component-memo-preview.h		\
 	e-cal-config.c				\
 	e-cal-config.h				\
 	e-cal-event.c				\
@@ -126,6 +129,8 @@
 	e-cal-list-view.h			\
 	e-cal-list-view-config.c		\
 	e-cal-list-view-config.h		\
+	e-cal-model-memos.c			\
+	e-cal-model-memos.h			\
 	e-calendar-table.c			\
 	e-calendar-table.h			\
 	e-calendar-table-config.c		\
@@ -167,6 +172,12 @@
 	e-meeting-types.h			\
 	e-meeting-utils.c			\
 	e-meeting-utils.h			\
+	e-memo-table.c				\
+	e-memo-table.h				\
+	e-memo-table-config.c			\
+	e-memo-table-config.h			\
+	e-memos.c				\
+	e-memos.h				\
 	e-mini-calendar-config.c		\
 	e-mini-calendar-config.h		\
 	e-pub-utils.c				\
@@ -200,6 +211,10 @@
 	itip-utils.c				\
 	itip-utils.h				\
 	main.c					\
+	memos-component.c			\
+	memos-component.h			\
+	memos-control.c				\
+	memos-control.h				\
 	migration.c				\
 	migration.h				\
 	misc.c					\
Index: calendar/gui/calendar-config-keys.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-config-keys.h,v
retrieving revision 1.9
diff -u -r1.9 calendar-config-keys.h
--- calendar/gui/calendar-config-keys.h	30 May 2005 09:14:26 -0000	1.9
+++ calendar/gui/calendar-config-keys.h	26 Jul 2005 03:36:24 -0000
@@ -64,6 +64,11 @@
 #define CALENDAR_CONFIG_TASKS_DUE_TODAY_COLOR CALENDAR_CONFIG_PREFIX "/tasks/colors/due_today"
 #define CALENDAR_CONFIG_TASKS_OVERDUE_COLOR CALENDAR_CONFIG_PREFIX "/tasks/colors/overdue"
 
+/* Memo display settings */
+#define CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS CALENDAR_CONFIG_PREFIX "/memos/selected_memos"
+#define CALENDAR_CONFIG_PRIMARY_MEMOS CALENDAR_CONFIG_PREFIX "/memos/primary_memos"
+
+
 /* Prompt settings */
 #define CALENDAR_CONFIG_PROMPT_DELETE CALENDAR_CONFIG_PREFIX "/prompts/confirm_delete"
 #define CALENDAR_CONFIG_PROMPT_PURGE CALENDAR_CONFIG_PREFIX "/prompts/confirm_purge"
Index: calendar/gui/calendar-config.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-config.c,v
retrieving revision 1.77
diff -u -r1.77 calendar-config.c
--- calendar/gui/calendar-config.c	13 Jul 2005 10:36:14 -0000	1.77
+++ calendar/gui/calendar-config.c	26 Jul 2005 03:36:25 -0000
@@ -633,6 +633,55 @@
 	gconf_client_set_int (config, CALENDAR_CONFIG_TASK_VPANE_POS, vpane_pos, NULL);
 }
 
+/***************************************/
+
+/* The current list of memo lists selected */
+GSList   *
+calendar_config_get_memos_selected (void)
+{
+	return gconf_client_get_list (config, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, NULL);
+}
+
+void
+calendar_config_set_memos_selected (GSList *selected)
+{
+	gconf_client_set_list (config, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, selected, NULL);
+}
+
+guint
+calendar_config_add_notification_memos_selected (GConfClientNotifyFunc func, gpointer data)
+{
+	guint id;
+	
+	id = gconf_client_notify_add (config, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, func, data, NULL, NULL);
+	
+	return id;
+}
+
+/* The primary memo list */
+char *
+calendar_config_get_primary_memos (void)
+{
+	return gconf_client_get_string (config, CALENDAR_CONFIG_PRIMARY_MEMOS, NULL);
+}
+
+void
+calendar_config_set_primary_memos (const char *primary_uid)
+{
+	gconf_client_set_string (config, CALENDAR_CONFIG_PRIMARY_MEMOS, primary_uid, NULL);
+}
+
+
+guint
+calendar_config_add_notification_primary_memos (GConfClientNotifyFunc func, gpointer data)
+{
+	guint id;
+	
+	id = gconf_client_notify_add (config, CALENDAR_CONFIG_PRIMARY_MEMOS, func, data, NULL, NULL);
+	
+	return id;
+}
+/***************************************/
 
 /* Whether we compress the weekend in the week/month views. */
 gboolean
Index: calendar/gui/calendar-config.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-config.h,v
retrieving revision 1.39
diff -u -r1.39 calendar-config.h
--- calendar/gui/calendar-config.h	30 May 2005 09:14:26 -0000	1.39
+++ calendar/gui/calendar-config.h	26 Jul 2005 03:36:25 -0000
@@ -163,6 +163,17 @@
 gint      calendar_config_get_task_vpane_pos    (void);
 void      calendar_config_set_task_vpane_pos    (gint         vpane_pos);
 
+
+/* The current list of memo lists selected */
+GSList   *calendar_config_get_memos_selected (void);
+void	  calendar_config_set_memos_selected (GSList *selected);
+guint	  calendar_config_add_notification_memos_selected (GConfClientNotifyFunc func, gpointer data);
+
+/* The primary calendar */
+char     *calendar_config_get_primary_memos (void);
+void	  calendar_config_set_primary_memos (const char *primary_uid);
+guint	  calendar_config_add_notification_primary_memos (GConfClientNotifyFunc func, gpointer data);
+
 /* Colors for the task list */
 const char *calendar_config_get_tasks_due_today_color	(void);
 void	    calendar_config_set_tasks_due_today_color	(const char *color);
Index: calendar/gui/comp-util.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/comp-util.c,v
retrieving revision 1.27
diff -u -r1.27 comp-util.c
--- calendar/gui/comp-util.c	24 Mar 2005 15:38:39 -0000	1.27
+++ calendar/gui/comp-util.c	26 Jul 2005 03:36:25 -0000
@@ -369,3 +369,22 @@
 
 	return comp;
 }
+
+ECalComponent *
+cal_comp_memo_new_with_defaults (ECal *client)
+{
+	ECalComponent *comp;
+	icalcomponent *icalcomp;
+
+	if (!e_cal_get_default_object (client, &icalcomp, NULL))
+		icalcomp = icalcomponent_new (ICAL_VJOURNAL_COMPONENT);
+	
+	comp = e_cal_component_new ();
+	if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+		icalcomponent_free (icalcomp);
+
+		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
+	}
+
+	return comp;
+}
Index: calendar/gui/comp-util.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/comp-util.h,v
retrieving revision 1.12
diff -u -r1.12 comp-util.h
--- calendar/gui/comp-util.h	15 Jan 2004 13:46:45 -0000	1.12
+++ calendar/gui/comp-util.h	26 Jul 2005 03:36:25 -0000
@@ -42,5 +42,6 @@
 ECalComponent *cal_comp_event_new_with_defaults (ECal *client);
 ECalComponent *cal_comp_event_new_with_current_time (ECal *client, gboolean all_day);
 ECalComponent *cal_comp_task_new_with_defaults (ECal *client);
+ECalComponent *cal_comp_memo_new_with_defaults (ECal *client);
 
 #endif
Index: calendar/gui/main.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/main.c,v
retrieving revision 1.173
diff -u -r1.173 main.c
--- calendar/gui/main.c	12 Jul 2005 04:04:10 -0000	1.173
+++ calendar/gui/main.c	26 Jul 2005 03:36:26 -0000
@@ -44,6 +44,7 @@
 #include "itip-bonobo-control.h"
 #include "tasks-control.h"
 #include "tasks-component.h"
+#include "memos-component.h"
 
 #include <e-util/e-plugin.h>
 #include <e-util/e-import.h>
@@ -57,6 +58,7 @@
 
 #define CALENDAR_COMPONENT_ID  "OAFIID:GNOME_Evolution_Calendar_Component:" BASE_VERSION
 #define TASKS_COMPONENT_ID     "OAFIID:GNOME_Evolution_Tasks_Component:" BASE_VERSION
+#define MEMOS_COMPONENT_ID     "OAFIID:GNOME_Evolution_Memos_Component:" BASE_VERSION
 #define ITIP_CONTROL_ID        "OAFIID:GNOME_Evolution_Calendar_iTip_Control:" BASE_VERSION
 #define CONFIG_CONTROL_ID      "OAFIID:GNOME_Evolution_Calendar_ConfigControl:" BASE_VERSION
 #define COMP_EDITOR_FACTORY_ID "OAFIID:GNOME_Evolution_Calendar_CompEditorFactory:" BASE_VERSION
@@ -179,6 +181,10 @@
 		BonoboObject *object = BONOBO_OBJECT (tasks_component_peek ());
 		bonobo_object_ref (object);
 		return object;
+	} else if (strcmp (component_id, MEMOS_COMPONENT_ID) == 0){
+		BonoboObject *object = BONOBO_OBJECT (memos_component_peek ());
+		bonobo_object_ref (object);
+		return object;
 	} else if (strcmp (component_id, ITIP_CONTROL_ID) == 0)
 		return BONOBO_OBJECT (itip_bonobo_control_new ());
 	else if (strcmp (component_id, CONFIG_CONTROL_ID) == 0)
Index: calendar/gui/migration.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/migration.c,v
retrieving revision 1.36
diff -u -r1.36 migration.c
--- calendar/gui/migration.c	9 May 2005 08:37:47 -0000	1.36
+++ calendar/gui/migration.c	26 Jul 2005 03:36:26 -0000
@@ -997,3 +997,123 @@
 	
         return retval;
 }
+
+/********************************************************************************************************
+ *
+ * 		MEMOS
+ * 
+ ********************************************************************************************************/
+
+static void
+create_memo_sources (MemosComponent *component,
+		     ESourceList   *source_list,
+		     ESourceGroup **on_this_computer,
+		     ESourceGroup **on_the_web,
+		     ESource **personal_source)
+{
+	GSList *groups;
+	ESourceGroup *group;
+	char *base_uri, *base_uri_proto;
+
+	*on_this_computer = NULL;
+	*on_the_web = NULL;
+	*personal_source = NULL;
+	
+	base_uri = g_build_filename (memos_component_peek_base_directory (component),
+				     "memos", "local", NULL);
+
+	base_uri_proto = g_strconcat ("file://", base_uri, NULL);
+
+	groups = e_source_list_peek_groups (source_list);
+	if (groups) {
+		/* groups are already there, we need to search for things... */
+		GSList *g;
+
+		for (g = groups; g; g = g->next) {
+
+			group = E_SOURCE_GROUP (g->data);
+
+			if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
+				*on_this_computer = g_object_ref (group);
+			else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
+				*on_the_web = g_object_ref (group);
+		}
+	}
+
+	if (*on_this_computer) {
+		/* make sure "Personal" shows up as a source under
+		   this group */
+		GSList *sources = e_source_group_peek_sources (*on_this_computer);
+		GSList *s;
+		for (s = sources; s; s = s->next) {
+			ESource *source = E_SOURCE (s->data);
+			if (!strcmp (PERSONAL_RELATIVE_URI, e_source_peek_relative_uri (source))) {
+				*personal_source = g_object_ref (source);
+				break;
+			}
+		}
+	} else {
+		/* create the local source group */
+		group = e_source_group_new (_("On This Computer"), base_uri_proto);
+		e_source_list_add_group (source_list, group, -1);
+
+		*on_this_computer = group;
+	}
+
+	if (!*personal_source) {
+		/* Create the default Person task list */
+		ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
+		e_source_group_add_source (*on_this_computer, source, -1);
+
+		if (!calendar_config_get_primary_memos () && !calendar_config_get_memos_selected ()) {
+			GSList selected;
+
+			calendar_config_set_primary_memos (e_source_peek_uid (source));
+
+			selected.data = (gpointer)e_source_peek_uid (source);
+			selected.next = NULL;
+			calendar_config_set_memos_selected (&selected);
+		}
+
+		e_source_set_color (source, 0xBECEDD);
+		*personal_source = source;
+	}
+
+	if (!*on_the_web) {
+		/* Create the Webcal source group */
+		group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
+		e_source_list_add_group (source_list, group, -1);
+
+		*on_the_web = group;
+	}
+
+	g_free (base_uri_proto);
+	g_free (base_uri);
+}
+
+
+gboolean
+migrate_memos (MemosComponent *component, int major, int minor, int revision, struct _GError **err)
+{
+	ESourceGroup *on_this_computer = NULL;
+	ESourceGroup *on_the_web = NULL;
+	ESource *personal_source = NULL;
+	gboolean retval = FALSE;
+
+	/* we call this unconditionally now - create_groups either
+	   creates the groups/sources or it finds the necessary
+	   groups/sources. */
+	create_memo_sources (component, memos_component_peek_source_list (component), &on_this_computer, &on_the_web, &personal_source);
+
+	e_source_list_sync (memos_component_peek_source_list (component), NULL);
+	retval = TRUE;
+fail:
+	if (on_this_computer)
+		g_object_unref (on_this_computer);
+	if (on_the_web)
+		g_object_unref (on_the_web);
+	if (personal_source)
+		g_object_unref (personal_source);
+	
+        return retval;
+}
Index: calendar/gui/migration.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/migration.h,v
retrieving revision 1.6
diff -u -r1.6 migration.h
--- calendar/gui/migration.h	12 May 2004 03:32:19 -0000	1.6
+++ calendar/gui/migration.h	26 Jul 2005 03:36:26 -0000
@@ -26,10 +26,11 @@
 #include <libedataserver/e-source-group.h>
 #include "calendar-component.h"
 #include "tasks-component.h"
+#include "memos-component.h"
 
 struct _GError;
 
 gboolean migrate_calendars (CalendarComponent *component, int major, int minor, int revision, struct _GError **err);
 gboolean migrate_tasks (TasksComponent *component, int major, int minor, int revision, struct _GError **err);
-
+gboolean migrate_memos (MemosComponent *component, int major, int minor, int revision, struct _GError **err);
 #endif
Index: calendar/gui/dialogs/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/Makefile.am,v
retrieving revision 1.72
diff -u -r1.72 Makefile.am
--- calendar/gui/dialogs/Makefile.am	11 Jul 2005 08:59:38 -0000	1.72
+++ calendar/gui/dialogs/Makefile.am	26 Jul 2005 03:36:27 -0000
@@ -51,6 +51,10 @@
 	event-editor.h		\
 	event-page.c		\
 	event-page.h		\
+	memo-editor.c		\
+	memo-editor.h		\
+	memo-page.c		\
+	memo-page.h		\
 	meeting-page.c		\
 	meeting-page.h		\
 	recurrence-page.c	\
@@ -72,7 +76,7 @@
 	task-page.c		\
 	task-page.h		\
 	url-editor-dialog.c	\
-	url-editor-dialog.h	
+	url-editor-dialog.h
 
 glade_DATA =				\
 	alarm-dialog.glade		\
@@ -81,6 +85,7 @@
 	e-delegate-dialog.glade		\
 	event-page.glade		\
 	meeting-page.glade		\
+	memo-page.glade			\
 	recurrence-page.glade		\
 	schedule-page.glade		\
 	task-details-page.glade		\
Index: calendar/gui/dialogs/calendar-setup.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/calendar-setup.c,v
retrieving revision 1.37
diff -u -r1.37 calendar-setup.c
--- calendar/gui/dialogs/calendar-setup.c	1 Jul 2005 09:49:32 -0000	1.37
+++ calendar/gui/dialogs/calendar-setup.c	26 Jul 2005 03:36:28 -0000
@@ -288,6 +288,12 @@
 		else if (sdialog->source_type == E_CAL_SOURCE_TYPE_TODO)	
 
 			offline_setting = gtk_check_button_new_with_label (N_("Copy task list contents locally for offline operation"));
+		else if(sdialog->source_type == E_CAL_SOURCE_TYPE_JOURNAL)
+			offline_setting = gtk_check_button_new_with_label(N_("Copy memo list contents locally for offline operation"));
+		else{
+			g_warning("Unknown source type: %p", sdialog->source_type);
+			return NULL;
+		}
 
 		gtk_widget_show (offline_setting);
 		g_signal_connect (offline_setting, "toggled", G_CALLBACK (offline_status_changed_cb), sdialog);
@@ -385,6 +391,17 @@
 	{ 0 },
 };
 
+static ECalConfigItem ecmp_items[] = {
+	{ E_CONFIG_BOOK, "", NULL },
+	{ E_CONFIG_PAGE,          "00.general", N_("General") },
+	{ E_CONFIG_SECTION_TABLE, "00.general/00.source", N_("Memos List") },
+	{ E_CONFIG_ITEM_TABLE,    "00.general/00.source/00.type", NULL, eccp_get_source_type },
+	{ E_CONFIG_ITEM_TABLE,    "00.general/00.source/10.name", NULL, eccp_get_source_name },
+	{ E_CONFIG_ITEM_TABLE,    "00.general/00.source/20.color", NULL, eccp_get_source_color },
+	{ E_CONFIG_ITEM_TABLE,	  "00.general/00.source/30.offline", NULL, eccp_general_offline },
+	{ 0 },
+};
+
 /**
  * calendar_setup_edit_calendar:
  * @parent: parent window for dialog (current unused)
@@ -528,3 +545,69 @@
 {
 	calendar_setup_edit_task_list (parent, NULL);
 }
+
+void
+calendar_setup_edit_memo_list (struct _GtkWindow *parent, ESource *source)
+{
+	CalendarSourceDialog *sdialog = g_new0 (CalendarSourceDialog, 1);
+	char *xml;
+	ECalConfig *ec;
+	int i;
+	GSList *items = NULL;
+	ECalConfigTargetSource *target;
+
+	if (source) {
+		guint32 color;
+
+		sdialog->original_source = source;
+		g_object_ref (source);
+		sdialog->source_group = e_source_peek_group (source);
+		xml = e_source_to_standalone_xml (source);
+		sdialog->source = e_source_new_from_standalone_xml (xml);
+		g_free (xml);
+
+		e_source_get_color (source, &color);
+		e_source_set_color (sdialog->source, color);
+	} else {
+		GConfClient *gconf;
+		GSList *l;
+
+		sdialog->source = e_source_new ("", "");
+		gconf = gconf_client_get_default ();
+		sdialog->source_list = e_source_list_new_for_gconf (gconf, "/apps/evolution/memos/sources");
+		l = e_source_list_peek_groups (sdialog->source_list);
+		sdialog->menu_source_groups = g_slist_copy(l);
+
+		sdialog->source_group = (ESourceGroup *)sdialog->menu_source_groups->data;
+		g_object_unref (gconf);
+	}
+
+	/* HACK: doesn't work if you don't do this */
+	e_source_set_absolute_uri (sdialog->source, NULL);
+	e_source_set_group (sdialog->source, sdialog->source_group);
+
+	sdialog->source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+	sdialog->config = ec = e_cal_config_new (E_CONFIG_BOOK, "org.gnome.evolution.calendar.calendarProperties");
+	for (i = 0; ecmp_items[i].path; i++)
+		items = g_slist_prepend (items, &ecmp_items[i]);
+	e_config_add_items ((EConfig *) ec, items, eccp_commit, NULL, eccp_free, sdialog);
+	e_config_add_page_check ((EConfig *) ec, NULL, eccp_check_complete, sdialog);
+
+	target = e_cal_config_target_new_source (ec, sdialog->source);
+	target->source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+	e_config_set_target ((EConfig *) ec, (EConfigTarget *) target);
+
+	sdialog->window = e_config_create_window ((EConfig *)ec, NULL, _("New Memo List"));
+
+	/* forces initial validation */
+	if (!sdialog->original_source)
+		e_config_target_changed ((EConfig *)ec, E_CONFIG_TARGET_CHANGED_STATE);
+
+	return;
+}
+
+void
+calendar_setup_new_memo_list (struct _GtkWindow *parent)
+{
+	calendar_setup_edit_memo_list (parent, NULL);
+}
Index: calendar/gui/dialogs/calendar-setup.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/calendar-setup.h,v
retrieving revision 1.3
diff -u -r1.3 calendar-setup.h
--- calendar/gui/dialogs/calendar-setup.h	25 Nov 2004 14:51:18 -0000	1.3
+++ calendar/gui/dialogs/calendar-setup.h	26 Jul 2005 03:36:28 -0000
@@ -36,6 +36,9 @@
 void calendar_setup_edit_task_list (struct _GtkWindow *parent, struct _ESource *source);
 void calendar_setup_new_task_list  (struct _GtkWindow *parent);
 
+void calendar_setup_edit_memo_list (struct _GtkWindow *parent, ESource *source);
+void calendar_setup_new_memo_list (struct _GtkWindow *parent);
+
 #ifdef __cplusplus
 }
 #endif
Index: calendar/gui/dialogs/send-comp.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/send-comp.c,v
retrieving revision 1.17
diff -u -r1.17 send-comp.c
--- calendar/gui/dialogs/send-comp.c	16 May 2005 06:13:14 -0000	1.17
+++ calendar/gui/dialogs/send-comp.c	26 Jul 2005 03:36:28 -0000
@@ -90,7 +90,8 @@
 	case E_CAL_COMPONENT_TODO:
 			id = "calendar:prompt-send-no-subject-task";
 		break;
-
+	case E_CAL_COMPONENT_JOURNAL:
+			return TRUE; /* we don't do summaries directly */
 	default:
 		g_message ("send_component_prompt_subject(): "
 			   "Cannot handle object of type %d", vtype);
Index: ui/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/ui/ChangeLog,v
retrieving revision 1.417
diff -u -r1.417 ChangeLog
--- ui/ChangeLog	25 Jul 2005 07:53:17 -0000	1.417
+++ ui/ChangeLog	26 Jul 2005 03:36:30 -0000
@@ -1,3 +1,7 @@
+2005-07-25  Nathan Owens <pianocomp81 yahoo com
+	* evolution-memos.xml: added menus for memos component
+	* Makefile.am: added evolution-memos.xml to build files
+
 2005-07-25  Viren.l <lviren novell com>
 
 	* evolution-tasks.xml: Added 2 submenus under action menu.
Index: ui/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/ui/Makefile.am,v
retrieving revision 1.25
diff -u -r1.25 Makefile.am
--- ui/Makefile.am	4 Jan 2005 19:38:07 -0000	1.25
+++ ui/Makefile.am	26 Jul 2005 03:36:30 -0000
@@ -8,6 +8,7 @@
 	evolution-mail-list.xml			\
 	evolution-mail-global.xml		\
 	evolution-mail-messagedisplay.xml	\
+	evolution-memos.xml			\
 	evolution-message-composer.xml		\
 	evolution-signature-editor.xml		\
 	evolution-subscribe.xml			\
Index: views/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/views/ChangeLog,v
retrieving revision 1.23
diff -u -r1.23 ChangeLog
--- views/ChangeLog	9 Aug 2004 19:09:14 -0000	1.23
+++ views/ChangeLog	26 Jul 2005 03:36:30 -0000
@@ -1,3 +1,9 @@
+2005-07-25  Nathan Owens <pianocomp81 yahoo com>
+	
+	* Makefile.am: added memos directory
+	* views/memos/*: added galview.xml, Makefile.am, Memos.galview for
+	initial Memos component
+
 2004-08-06  Chris Toshok  <toshok ximian com>
 
 	[ fixes bug #52459 ]
Index: views/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/views/Makefile.am,v
retrieving revision 1.4
diff -u -r1.4 Makefile.am
--- views/Makefile.am	12 Jun 2003 21:13:33 -0000	1.4
+++ views/Makefile.am	26 Jul 2005 03:36:30 -0000
@@ -1,3 +1,3 @@
-SUBDIRS = addressbook mail tasks calendar
+SUBDIRS = addressbook mail tasks calendar memos
 
 EXTRA_DIST = ChangeLog.pre-1-4
Index: calendar/conduits/memo/Makefile.am
===================================================================
RCS file: calendar/conduits/memo/Makefile.am
diff -N calendar/conduits/memo/Makefile.am
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/conduits/memo/Makefile.am	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,37 @@
+INCLUDES = 					\
+	-I$(top_srcdir)/e-util			\
+	-I$(top_builddir)/e-util		\
+	-I$(top_srcdir)/widgets/misc		\
+	-I$(top_builddir)/widgets/misc		\
+	$(EVOLUTION_CALENDAR_CONDUIT_CFLAGS)
+
+# Memo Conduit
+privconduit_LTLIBRARIES = libememo_conduit.la
+
+libememo_conduit_la_SOURCES = 	\
+	memo-conduit.c
+
+libememo_conduit_la_LDFLAGS = -module -avoid-version
+libememo_conduit_la_LIBADD = 						\
+	$(top_builddir)/e-util/libeutil.la				\
+	$(top_builddir)/e-util/libeconduit.la		 		\
+	$(top_builddir)/widgets/misc/libemiscwidgets.la		 	\
+	$(EVOLUTION_CALENDAR_CONDUIT_LIBS)
+
+e-memo-$(BASE_VERSION).conduit: e-memo.conduit.in
+	sed -e 's^\ privconduitdir\@^$(privconduitdir)^g' 			\
+	    -e 's^\ datadir\@^$(datadir)^g' 				\
+	    -e 's^\ BASE_VERSION\@^$(BASE_VERSION)^g' 			\
+	    $< > $@
+
+conduitdir = $(datadir)/gnome-pilot/conduits/
+conduit_DATA = e-memo-$(BASE_VERSION).conduit
+
+BUILT_SOURCES = $(conduit_DATA)
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+	e-memo.conduit.in
+
+dist-hook:
+	cd $(distdir); rm -f $(BUILT_SOURCES)
Index: calendar/conduits/memo/e-memo.conduit.in
===================================================================
RCS file: calendar/conduits/memo/e-memo.conduit.in
diff -N calendar/conduits/memo/e-memo.conduit.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/conduits/memo/e-memo.conduit.in	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+<gnome-pilot-conduit version="1.0">
+	<conduit id="e_memo_conduit" type="shlib" location="@privconduitdir@/libememo_conduit.so"/>
+	<name value="EMemos"/>
+	<conduit-attribute name="description" value="Synchronizes Memo List with Evolution @BASE_VERSION@"/>
+	<conduit-attribute name="default-synctype" value="synchronize"/>
+	<conduit-attribute name="valid-synctypes" value="synchronize copy_from_pilot copy_to_pilot"/>
+     	<conduit-attribute name="settings" value="TRUE"/>
+</gnome-pilot-conduit>
Index: calendar/conduits/memo/memo-conduit.c
===================================================================
RCS file: calendar/conduits/memo/memo-conduit.c
diff -N calendar/conduits/memo/memo-conduit.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/conduits/memo/memo-conduit.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1445 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Evolution calendar - Memo Conduit
+ *
+ * Copyright (C) 1998 Free Software Foundation
+ * Copyright (C) 2000 Ximian, Inc.
+ *
+ * Authors: Eskil Heyn Olsen <deity eskil dk> 
+ *          JP Rosevear <jpr ximian com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define G_LOG_DOMAIN "ememoconduit"
+
+#include <libecal/e-cal-types.h>
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-time-util.h>
+#include <libedataserver/e-categories.h>
+#include <pi-source.h>
+#include <pi-socket.h>
+#include <pi-dlp.h>
+#include <pi-memo.h>
+#include <libical/icaltypes.h>
+#include <gpilotd/gnome-pilot-conduit.h>
+#include <gpilotd/gnome-pilot-conduit-sync-abs.h>
+#include <libgpilotdCM/gnome-pilot-conduit-management.h>
+#include <libgpilotdCM/gnome-pilot-conduit-config.h>
+#include <e-pilot-map.h>
+#include <e-pilot-settings.h>
+#include <e-pilot-util.h>
+#include <e-config-listener.h>
+
+GnomePilotConduit * conduit_get_gpilot_conduit (guint32);
+void conduit_destroy_gpilot_conduit (GnomePilotConduit*);
+
+#define CONDUIT_VERSION "0.1.6"
+
+#define DEBUG_MEMOCONDUIT 1
+/* #undef DEBUG_MEMOCONDUIT */
+
+#ifdef DEBUG_MEMOCONDUIT
+#define LOG(x) x
+#else
+#define LOG(x)
+#endif
+
+#define WARN g_warning
+#define INFO g_message
+
+typedef struct _EMemoLocalRecord EMemoLocalRecord;
+typedef struct _EMemoConduitCfg EMemoConduitCfg;
+typedef struct _EMemoConduitGui EMemoConduitGui;
+typedef struct _EMemoConduitContext EMemoConduitContext;
+
+/* Local Record */
+struct _EMemoLocalRecord {
+	/* The stuff from gnome-pilot-conduit-standard-abs.h
+	   Must be first in the structure, or instances of this
+	   structure cannot be used by gnome-pilot-conduit-standard-abs.
+	*/
+	GnomePilotDesktopRecord local;
+
+	/* The corresponding Comp object */
+	ECalComponent *comp;
+
+        /* pilot-link memo structure */
+	struct Memo *memo;
+};
+
+int lastDesktopUniqueID;
+
+static void
+memoconduit_destroy_record (EMemoLocalRecord *local) 
+{
+	g_object_unref (local->comp);
+	free_Memo (local->memo);
+	g_free (local->memo);	
+	g_free (local);
+}
+
+/* Configuration */
+struct _EMemoConduitCfg {
+	guint32 pilot_id;
+	GnomePilotConduitSyncType  sync_type;
+
+	ESourceList *source_list;
+	ESource *source;
+	gboolean secret;
+	gint priority;
+
+	gchar *last_uri;
+};
+
+static EMemoConduitCfg *
+memoconduit_load_configuration (guint32 pilot_id) 
+{
+	EMemoConduitCfg *c;
+	GnomePilotConduitManagement *management;
+	GnomePilotConduitConfig *config;
+	gchar prefix[256];
+
+
+	g_snprintf (prefix, 255, "/gnome-pilot.d/e-memo-conduit/Pilot_%u/",
+		    pilot_id);
+	
+	c = g_new0 (EMemoConduitCfg,1);
+	g_assert (c != NULL);
+
+	c->pilot_id = pilot_id;
+
+	management = gnome_pilot_conduit_management_new ("e_memo_conduit", GNOME_PILOT_CONDUIT_MGMT_ID);
+	gtk_object_ref (GTK_OBJECT (management));
+	gtk_object_sink (GTK_OBJECT (management));
+	config = gnome_pilot_conduit_config_new (management, pilot_id);
+	gtk_object_ref (GTK_OBJECT (config));
+	gtk_object_sink (GTK_OBJECT (config));
+	if (!gnome_pilot_conduit_config_is_enabled (config, &c->sync_type))
+		c->sync_type = GnomePilotConduitSyncTypeNotSet;
+	gtk_object_unref (GTK_OBJECT (config));
+	gtk_object_unref (GTK_OBJECT (management));
+	
+	/* Custom settings */
+	gnome_config_push_prefix (prefix);
+	
+	if (!e_cal_get_sources (&c->source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL))
+		c->source_list = NULL;
+	if (c->source_list) {
+		c->source = e_pilot_get_sync_source (c->source_list);
+		if (!c->source)
+			c->source = e_source_list_peek_source_any (c->source_list);
+		if (c->source) {
+			g_object_ref (c->source);
+		} else {
+			g_object_unref (c->source_list);
+			c->source_list = NULL;
+		}
+	}
+	
+	c->secret = gnome_config_get_bool ("secret=FALSE");
+	c->priority = gnome_config_get_int ("priority=3");
+	c->last_uri = gnome_config_get_string ("last_uri");
+
+	gnome_config_pop_prefix ();
+
+	return c;
+}
+
+static void
+memoconduit_save_configuration (EMemoConduitCfg *c) 
+{
+	gchar prefix[256];
+
+	g_snprintf (prefix, 255, "/gnome-pilot.d/e-memo-conduit/Pilot_%u/",
+		    c->pilot_id);
+
+	gnome_config_push_prefix (prefix);
+	e_pilot_set_sync_source (c->source_list, c->source);
+	gnome_config_set_bool ("secret", c->secret);
+	gnome_config_set_int ("priority", c->priority);
+	gnome_config_set_string ("last_uri", c->last_uri);
+	gnome_config_pop_prefix ();
+
+	gnome_config_sync ();
+	gnome_config_drop_all ();
+}
+
+static EMemoConduitCfg*
+memoconduit_dupe_configuration (EMemoConduitCfg *c) 
+{
+	EMemoConduitCfg *retval;
+
+	g_return_val_if_fail (c != NULL, NULL);
+
+	retval = g_new0 (EMemoConduitCfg, 1);
+	retval->sync_type = c->sync_type;
+	retval->pilot_id = c->pilot_id;
+
+	if (c->source_list)
+		retval->source_list = g_object_ref (c->source_list);
+	if (c->source)
+		retval->source = g_object_ref (c->source);
+	retval->secret = c->secret;
+	retval->priority = c->priority;
+	retval->last_uri = g_strdup (c->last_uri);
+
+	return retval;
+}
+
+static void 
+memoconduit_destroy_configuration (EMemoConduitCfg *c) 
+{
+	g_return_if_fail (c != NULL);
+
+	g_object_unref (c->source_list);
+	g_object_unref (c->source);
+	g_free (c->last_uri);
+	g_free (c);
+}
+
+/* Context */
+struct _EMemoConduitContext {
+	GnomePilotDBInfo *dbi;
+
+	EMemoConduitCfg *cfg;
+	EMemoConduitCfg *new_cfg;
+	GtkWidget *ps;
+	
+	struct MemoAppInfo ai;
+
+	ECal *client;
+
+	icaltimezone *timezone;
+	ECalComponent *default_comp;
+	GList *comps;
+	GList *changed;
+	GHashTable *changed_hash;
+	GList *locals;
+	
+	EPilotMap *map;
+};
+
+static EMemoConduitContext *
+e_memo_context_new (guint32 pilot_id) 
+{
+	EMemoConduitContext *ctxt = g_new0 (EMemoConduitContext, 1);
+	
+	ctxt->cfg = memoconduit_load_configuration (pilot_id);
+	ctxt->new_cfg = memoconduit_dupe_configuration (ctxt->cfg);
+	ctxt->ps = NULL;
+	ctxt->client = NULL;
+	ctxt->timezone = NULL;
+	ctxt->default_comp = NULL;
+	ctxt->comps = NULL;
+	ctxt->changed_hash = NULL;
+	ctxt->changed = NULL;
+	ctxt->locals = NULL;
+	ctxt->map = NULL;
+
+	return ctxt;
+}
+
+static gboolean
+e_memo_context_foreach_change (gpointer key, gpointer value, gpointer data) 
+{
+	g_free (key);
+	
+	return TRUE;
+}
+
+static void
+e_memo_context_destroy (EMemoConduitContext *ctxt)
+{
+	GList *l;
+	
+	g_return_if_fail (ctxt != NULL);
+
+	if (ctxt->cfg != NULL)
+		memoconduit_destroy_configuration (ctxt->cfg);
+	if (ctxt->new_cfg != NULL)
+		memoconduit_destroy_configuration (ctxt->new_cfg);
+	
+	if (ctxt->client != NULL)
+		g_object_unref (ctxt->client);
+
+	if (ctxt->default_comp != NULL)
+		g_object_unref (ctxt->default_comp);
+	if (ctxt->comps != NULL) {
+		for (l = ctxt->comps; l; l = l->next)
+			g_object_unref (l->data);
+		g_list_free (ctxt->comps);
+	}
+
+	if (ctxt->changed_hash != NULL) {
+		g_hash_table_foreach_remove (ctxt->changed_hash, e_memo_context_foreach_change, NULL);
+		g_hash_table_destroy (ctxt->changed_hash);
+	}
+
+	if (ctxt->locals != NULL) {
+		for (l = ctxt->locals; l != NULL; l = l->next)
+			memoconduit_destroy_record (l->data);
+		g_list_free (ctxt->locals);
+	}
+	
+	if (ctxt->changed != NULL)
+		e_cal_free_change_list (ctxt->changed);
+	
+	if (ctxt->map != NULL)
+		e_pilot_map_destroy (ctxt->map);
+
+	g_free (ctxt);
+}
+
+/* Debug routines */
+static char *
+print_local (EMemoLocalRecord *local)
+{
+	static char buff[ 64 ];
+
+	if (local == NULL) {
+		sprintf (buff, "[NULL]");
+		return buff;
+	}
+
+	if (local->memo && local->memo->text) {
+		g_snprintf (buff, 64, "['%s']",
+			    local->memo->text ?
+			    local->memo->text : "");
+		return buff;
+	}
+
+	return "";
+}
+
+static char *print_remote (GnomePilotRecord *remote)
+{
+	static char buff[ 64 ];
+	struct Memo memo;
+
+	if (remote == NULL) {
+		sprintf (buff, "[NULL]");
+		return buff;
+	}
+
+	memset (&memo, 0, sizeof (struct Memo));
+	unpack_Memo (&memo, remote->record, remote->length);
+
+	g_snprintf (buff, 64, "['%s']",
+		    memo.text ?
+		    memo.text : "");
+
+	free_Memo (&memo);
+	
+	return buff;
+}
+
+static int
+start_calendar_server (EMemoConduitContext *ctxt)
+{
+	g_return_val_if_fail (ctxt != NULL, -2);
+
+	if (ctxt->cfg->source) {
+		ctxt->client = e_cal_new (ctxt->cfg->source, E_CAL_SOURCE_TYPE_JOURNAL);
+		if (!e_cal_open (ctxt->client, TRUE, NULL)) 
+			return -1;
+	} else if (!e_cal_open_default (&ctxt->client, E_CAL_SOURCE_TYPE_JOURNAL, NULL, NULL, NULL)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static icaltimezone *
+get_default_timezone (void)
+{
+	EConfigListener *listener;
+	icaltimezone *timezone = NULL;
+	char *location;
+
+	listener = e_config_listener_new ();
+
+	location = e_config_listener_get_string_with_default (listener,
+		"/apps/evolution/calendar/display/timezone", "UTC", NULL);
+	if (!location || !location[0]) {
+		g_free (location);
+		location = g_strdup ("UTC");
+	}
+	
+	timezone = icaltimezone_get_builtin_timezone (location);
+	g_free (location);
+
+	g_object_unref (listener);
+
+	return timezone;	
+}
+
+static char *
+map_name (EMemoConduitContext *ctxt) 
+{
+	char *filename;
+	
+	filename = g_strdup_printf ("%s/.evolution/memos/local/system/pilot-map-memo-%d.xml", g_get_home_dir (), ctxt->cfg->pilot_id);
+	
+	return filename;
+}
+
+static GList *
+next_changed_item (EMemoConduitContext *ctxt, GList *changes) 
+{
+	ECalChange *ccc;
+	GList *l;
+	
+	for (l = changes; l != NULL; l = l->next) {
+		const char *uid;
+
+		ccc = l->data;
+		
+		e_cal_component_get_uid (ccc->comp, &uid);
+		if (g_hash_table_lookup (ctxt->changed_hash, uid))
+			return l;
+	}
+	
+	return NULL;
+}
+
+static void
+compute_status (EMemoConduitContext *ctxt, EMemoLocalRecord *local, const char *uid)
+{
+	ECalChange *ccc;
+
+	local->local.archived = FALSE;
+	local->local.secret = FALSE;
+
+	ccc = g_hash_table_lookup (ctxt->changed_hash, uid);
+	
+	if (ccc == NULL) {
+		local->local.attr = GnomePilotRecordNothing;
+		return;
+	}
+	
+	switch (ccc->type) {
+	case E_CAL_CHANGE_ADDED:
+		local->local.attr = GnomePilotRecordNew;
+		break;	
+	case E_CAL_CHANGE_MODIFIED:
+		local->local.attr = GnomePilotRecordModified;
+		break;
+	case E_CAL_CHANGE_DELETED:
+		local->local.attr = GnomePilotRecordDeleted;
+		break;
+	}
+}
+
+static GnomePilotRecord
+local_record_to_pilot_record (EMemoLocalRecord *local,
+			      EMemoConduitContext *ctxt)
+{
+	GnomePilotRecord p;
+	static char record[0xffff];
+
+	g_assert (local->comp != NULL);
+	g_assert (local->memo != NULL );
+	
+	LOG (g_message ( "local_record_to_pilot_record\n" ));
+
+	p.ID = local->local.ID;
+	p.category = local->local.category;
+	p.attr = local->local.attr;
+	p.archived = local->local.archived;
+	p.secret = local->local.secret;
+
+	/* Generate pilot record structure */
+	p.record = record;
+	p.length = pack_Memo (local->memo, p.record, 0xffff);
+
+	return p;	
+}
+
+/*
+ * Adds a category to the category app info structure (name and ID),
+ * sets category->renamed[i] to true if possible to rename.
+ * 
+ * This will be packed and written to the app info block during post_sync.
+ */
+ 
+static int
+add_category_if_possible(char *cat_to_add, struct CategoryAppInfo *category)
+{
+	int i, j;
+	int retval = 0; /* 0 is the Unfiled category */
+	LOG(fprintf(stderr, "add_category_if_possible: called\n"));
+	
+	for(i=0; i<16; i++){
+		/* if strlen is 0, then the category is empty
+		   the PalmOS doesn't let 0-length strings for
+		   categories */
+		LOG(fprintf(stderr, "add_category_if_possible: calling strlen, i==%d\n", i));
+		if(strlen(category->name[i]) == 0){
+			int cat_to_add_len;
+			LOG(fprintf(stderr, "add_category_if_possible: strlen == 0\n"));
+			
+			cat_to_add_len = strlen(cat_to_add);
+			LOG(fprintf(stderr, "add_category_if_possible: cat_to_add_len: %d\n",
+					cat_to_add_len));
+			retval = i;
+			
+			/* only 15 characters for category, 16th is
+			 * '\0' can't do direct mem transfer due to
+			 * declaration type
+			 */
+			LOG(fprintf(stderr, "add_category_if_possible: copying first 15 of category\n"));
+			for(j=0; j<cat_to_add_len; j++){
+				category->name[i][j] = cat_to_add[j];
+			}
+			LOG(fprintf(stderr,
+				"add_category_if_possible: setting from %d to i==15 to \\0\n",
+				cat_to_add_len));
+
+			for(j=cat_to_add_len; j<16; j++)
+				category->name[i][j] = '\0';
+			
+			LOG(fprintf(stderr, "add_category_if_possible: setting ID[%d] to %d\n",
+				category->ID[i], lastDesktopUniqueID));
+			category->ID[i] = lastDesktopUniqueID;
+			lastDesktopUniqueID++;
+			
+			LOG(fprintf(stderr, "add_category_if_possible: setting renamed[%d] to TRUE\n", i));
+			category->renamed[i] = TRUE;
+			
+			LOG(g_message("*** adding category '%s', ID %d ***",
+				category->name[i], category->ID[i]));
+			break;
+		}
+	}
+	
+	if(retval == 0){
+		LOG(g_message("*** not adding category - category list already full ***"));
+	}
+	
+	return retval;
+}
+
+/*
+ * converts a ECalComponent object to a EMemoLocalRecord
+ */
+static void
+local_record_from_comp (EMemoLocalRecord *local, ECalComponent *comp, EMemoConduitContext *ctxt) 
+{
+	const char *uid;
+	GSList *d_list = NULL;
+	ECalComponentText *description;
+	ECalComponentClassification classif;
+	
+	LOG (g_message ( "local_record_from_comp\n" ));
+
+	g_return_if_fail (local != NULL);
+	g_return_if_fail (comp != NULL);
+
+	local->comp = comp;
+	g_object_ref (comp);
+
+	LOG(fprintf(stderr, "local_record_from_comp: calling e_cal_component_get_uid\n"));
+	e_cal_component_get_uid (local->comp, &uid);
+	LOG(fprintf(stderr, "local_record_from_comp: got UID - %s, calling e_pilot_map_lookup_pid\n", uid));
+	local->local.ID = e_pilot_map_lookup_pid (ctxt->map, uid, TRUE);
+	LOG(fprintf(stderr, "local_record_from_comp: local->local.ID == %lu\n", local->local.ID));
+
+	compute_status (ctxt, local, uid);
+	
+	LOG(fprintf(stderr, "local_record_from_comp: local->local.attr: %d\n", local->local.attr));
+
+	local->memo = g_new0 (struct Memo,1);
+
+	/* Don't overwrite the category */
+	if (local->local.ID != 0) {
+		char record[0xffff];
+		int cat = 0;
+		
+		LOG(fprintf(stderr, "local_record_from_comp: calling dlp_ReadRecordById\n"));
+		if (dlp_ReadRecordById (ctxt->dbi->pilot_socket, 
+					ctxt->dbi->db_handle,
+					local->local.ID, &record, 
+					NULL, NULL, NULL, &cat) > 0) {
+			local->local.category = cat;
+		}
+		LOG(fprintf(stderr, "local_record_from_comp: done calling dlp_ReadRecordById\n"));
+	}
+	
+	/*
+	 * Grab category from existing category list in ctxt->ai.category
+	 */
+	if(local->local.category == 0){
+		GSList *categ_list_head, *categ_list_cur;
+		int cat = -1;
+		int i;
+		
+		LOG(fprintf(stderr, "local_record_from_comp: trying to set category"));
+		LOG(fprintf(stderr, "local_record_from_comp: calling e_cal_component_get_categories_list\n"));
+		
+		e_cal_component_get_categories_list(comp, &categ_list_head);
+		LOG(fprintf(stderr, "local_record_from_comp: got list, setting categ_list_cur to head\n"));
+		
+		categ_list_cur = categ_list_head;
+		while (categ_list_cur && cat == -1)
+		{	
+			LOG(fprintf(stderr, "local_record_from_comp: iterating, data == %s",
+				(char *)categ_list_cur->data));
+			for(i=0; i<16; i++){
+				LOG(fprintf(stderr, "local_record_from_comp: i == %d\n", i));
+				if(strcmp((char *)categ_list_cur->data,
+					  ctxt->ai.category.name[i]) == 0){
+					cat = i;
+					LOG(fprintf(stderr, "local_record_from_comp: found category, name: %s\n",
+							ctxt->ai.category.name[i]));
+					break;
+				}
+			}
+			
+			LOG(fprintf(stderr, "local_record_from_comp: calling g_slist_next\n"));
+			categ_list_cur = g_slist_next(categ_list_cur);
+		}
+		
+		if(cat != -1){
+			LOG(fprintf(stderr, "local_record_from_comp: setting category\n"));
+			local->local.category = cat;
+		}
+		else if(categ_list_head != NULL){
+			local->local.category =
+				add_category_if_possible(
+					(char *)(categ_list_head->data),
+					&(ctxt->ai.category));
+		}
+	}
+
+	/* STOP: don't replace these with g_strdup, since free_Memo
+	   uses free to deallocate */
+
+	e_cal_component_get_description_list (comp, &d_list);
+	if (d_list) {
+		description = (ECalComponentText *) d_list->data;
+		if (description && description->value){
+			local->memo->text = e_pilot_utf8_to_pchar (description->value);
+		}
+		else{
+			local->memo->text = NULL;
+		}
+	} else {
+		local->memo->text = NULL;
+	}
+	
+	e_cal_component_get_classification (comp, &classif);
+
+	if (classif == E_CAL_COMPONENT_CLASS_PRIVATE)
+		local->local.secret = 1;
+	else
+		local->local.secret = 0;
+
+	local->local.archived = 0;
+}
+
+static void 
+local_record_from_uid (EMemoLocalRecord *local,
+		       const char *uid,
+		       EMemoConduitContext *ctxt)
+{
+	ECalComponent *comp;
+	icalcomponent *icalcomp;
+	GError *error = NULL;
+
+	g_assert(local!=NULL);
+	
+	LOG(g_message("local_record_from_uid\n"));
+
+	if (e_cal_get_object (ctxt->client, uid, NULL, &icalcomp, &error)) {
+		comp = e_cal_component_new ();
+		if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+			g_object_unref (comp);
+			icalcomponent_free (icalcomp);
+			return;
+		}
+
+		local_record_from_comp (local, comp, ctxt);
+		g_object_unref (comp);
+	} else if (error->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
+		comp = e_cal_component_new ();
+		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
+		e_cal_component_set_uid (comp, uid);
+		local_record_from_comp (local, comp, ctxt);
+		g_object_unref (comp);
+	} else {
+		INFO ("Object did not exist");
+	}
+
+	g_clear_error (&error);
+}
+
+
+static ECalComponent *
+comp_from_remote_record (GnomePilotConduitSyncAbs *conduit,
+			 GnomePilotRecord *remote,
+			 ECalComponent *in_comp,
+			 icaltimezone *timezone,
+			 struct MemoAppInfo *ai)
+{
+	ECalComponent *comp;
+	struct Memo memo;
+	struct icaltimetype now;
+	icaltimezone *utc_zone;
+	char *txt, *txt2, *txt3;
+	char *category;
+	int i;
+	
+	g_return_val_if_fail (remote != NULL, NULL);
+
+	memset (&memo, 0, sizeof (struct Memo));
+	unpack_Memo (&memo, remote->record, remote->length);
+
+	utc_zone = icaltimezone_get_utc_timezone ();
+	now = icaltime_from_timet_with_zone (time (NULL), FALSE, 
+					     utc_zone);
+
+	if (in_comp == NULL) {
+		comp = e_cal_component_new ();
+		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
+		e_cal_component_set_created (comp, &now);
+	} else {
+		comp = e_cal_component_clone (in_comp);
+	}
+
+	e_cal_component_set_last_modified (comp, &now);
+	
+	/* The iCal description field */
+	if (!memo.text) {
+		e_cal_component_set_comment_list (comp, NULL);
+		e_cal_component_set_summary(comp, NULL);
+	} else {
+		int idxToUse = -1, ntext = strlen(memo.text);
+		gboolean foundNL = FALSE;
+		GSList l;
+		ECalComponentText text, sumText;
+
+		for(i = 0; i<ntext && i<50; i++){
+			if(memo.text[i] == '\n'){
+				idxToUse = i;
+				foundNL = TRUE;
+				break;
+			}
+		}
+		
+		if(foundNL == FALSE){
+			if(ntext > 50){
+				txt2 = g_strndup(memo.text, 50);
+			}
+			else{
+				txt2 = g_strdup(memo.text);
+				
+			}
+		}
+		else{
+			txt2 = g_strndup(memo.text, idxToUse); /* cuts off '\n' */
+			
+		}
+
+		sumText.value = txt3 = e_pilot_utf8_from_pchar(txt2);
+		sumText.altrep = NULL;
+
+		text.value = txt = e_pilot_utf8_from_pchar (memo.text);
+		text.altrep = NULL;
+		l.data = &text;
+		l.next = NULL;
+
+		e_cal_component_set_summary(comp, &sumText);
+		e_cal_component_set_description_list (comp, &l);
+		free (txt);
+		g_free(txt2);
+		free(txt3);
+	} 
+
+
+	e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_NONE);
+
+	if (remote->secret)
+		e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_PRIVATE);
+	else
+		e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_PUBLIC);
+	
+	
+	/* set the category properly */
+	category = ai->category.name[remote->category];
+	
+	/* TODO The Memos editor page and search bar are not updated until
+	  a restart of the evolution client */
+	if(e_categories_exist(category) == FALSE){
+		/* add if it doesn't exist */
+		e_categories_add(category, NULL, NULL, TRUE);
+	}
+	
+	e_cal_component_set_categories(comp, category);
+
+	e_cal_component_commit_sequence (comp);
+	
+	free_Memo(&memo);
+
+	return comp;
+}
+
+static void
+check_for_slow_setting (GnomePilotConduit *c, EMemoConduitContext *ctxt)
+{
+	GnomePilotConduitStandard *conduit = GNOME_PILOT_CONDUIT_STANDARD (c);
+	int map_count;
+	const char *uri;
+	
+	/* If there are no objects or objects but no log */
+	map_count = g_hash_table_size (ctxt->map->pid_map);
+	if (map_count == 0)
+		gnome_pilot_conduit_standard_set_slow (conduit, TRUE);
+
+	/* Or if the URI's don't match */
+	uri = e_cal_get_uri (ctxt->client);
+	LOG (g_message ( "  Current URI %s (%s)\n", uri, ctxt->cfg->last_uri ? ctxt->cfg->last_uri : "<NONE>" ));
+	if (ctxt->cfg->last_uri != NULL && (strcmp (ctxt->cfg->last_uri, uri) != 0)) {
+		gnome_pilot_conduit_standard_set_slow (conduit, TRUE);
+		e_pilot_map_clear (ctxt->map);
+	}
+
+	if (gnome_pilot_conduit_standard_get_slow (conduit)) {
+		ctxt->map->write_touched_only = TRUE;
+		LOG (g_message ( "    doing slow sync\n" ));
+	} else {
+		LOG (g_message ( "    doing fast sync\n" ));
+	}	
+}
+
+/* Pilot syncing callbacks */
+static gint
+pre_sync (GnomePilotConduit *conduit,
+	  GnomePilotDBInfo *dbi,
+	  EMemoConduitContext *ctxt)
+{
+	GnomePilotConduitSyncAbs *abs_conduit;
+	GList *l;
+	int len;
+	unsigned char *buf;
+	char *filename, *change_id;
+	icalcomponent *icalcomp;
+	gint num_records, add_records = 0, mod_records = 0, del_records = 0;
+
+	abs_conduit = GNOME_PILOT_CONDUIT_SYNC_ABS (conduit);
+
+	LOG (g_message ( "---------------------------------------------------------\n" ));
+	LOG (g_message ( "pre_sync: Memo Conduit v.%s", CONDUIT_VERSION ));
+	g_message ("Memo Conduit v.%s", CONDUIT_VERSION);
+
+	ctxt->dbi = dbi;	
+	ctxt->client = NULL;
+	
+	if (start_calendar_server (ctxt) != 0) {
+		WARN(_("Could not start evolution-data-server"));
+		gnome_pilot_conduit_error (conduit, _("Could not start evolution-data-server"));
+		return -1;
+	}
+
+	/* Get the timezone */
+	ctxt->timezone = get_default_timezone ();
+	if (ctxt->timezone == NULL)
+		return -1;
+	LOG (g_message ( "  Using timezone: %s", icaltimezone_get_tzid (ctxt->timezone) ));
+
+	/* Set the default timezone on the backend. */
+	if (ctxt->timezone && !e_cal_set_default_timezone (ctxt->client, ctxt->timezone, NULL))
+		return -1;
+	
+	/* Get the default component */
+	if (!e_cal_get_default_object (ctxt->client, &icalcomp, NULL))
+		return -1;
+	
+	ctxt->default_comp = e_cal_component_new ();
+	if (!e_cal_component_set_icalcomponent (ctxt->default_comp, icalcomp)) {
+		g_object_unref (ctxt->default_comp);
+		icalcomponent_free (icalcomp);
+		return -1;
+	}
+	
+	/* Load the uid <--> pilot id map */
+	filename = map_name (ctxt);
+	e_pilot_map_read (filename, &ctxt->map);
+	g_free (filename);
+
+	/* Get the local database */
+	if (!e_cal_get_object_list_as_comp (ctxt->client, "#t", &ctxt->comps, NULL))
+		return -1;
+	
+	/* Count and hash the changes */
+	change_id = g_strdup_printf ("pilot-sync-evolution-memo-%d", ctxt->cfg->pilot_id);
+	if (!e_cal_get_changes (ctxt->client, change_id, &ctxt->changed, NULL))
+		return -1;
+	
+	ctxt->changed_hash = g_hash_table_new (g_str_hash, g_str_equal);
+	g_free (change_id);
+	
+	for (l = ctxt->changed; l != NULL; l = l->next) {
+		ECalChange *ccc = l->data;
+		const char *uid;
+		
+		e_cal_component_get_uid (ccc->comp, &uid);
+		if (!e_pilot_map_uid_is_archived (ctxt->map, uid)) {
+			
+			g_hash_table_insert (ctxt->changed_hash, g_strdup (uid), ccc);
+			
+			switch (ccc->type) {
+			case E_CAL_CHANGE_ADDED:
+				add_records++;
+				break;
+			case E_CAL_CHANGE_MODIFIED:
+				mod_records++;
+				break;
+			case E_CAL_CHANGE_DELETED:
+				del_records++;
+				break;
+			}
+		} else if (ccc->type == E_CAL_CHANGE_DELETED) {
+			e_pilot_map_remove_by_uid (ctxt->map, uid);
+		}
+	}
+
+	/* Set the count information */
+	num_records = g_list_length (ctxt->comps);
+	gnome_pilot_conduit_sync_abs_set_num_local_records(abs_conduit, num_records);
+	gnome_pilot_conduit_sync_abs_set_num_new_local_records (abs_conduit, add_records);
+	gnome_pilot_conduit_sync_abs_set_num_updated_local_records (abs_conduit, mod_records);
+	gnome_pilot_conduit_sync_abs_set_num_deleted_local_records(abs_conduit, del_records);
+	
+	g_message("num_records: %d\nadd_records: %d\nmod_records: %d\ndel_records: %d\n",
+		num_records, add_records, mod_records, del_records);
+
+	buf = (unsigned char*)g_malloc (0xffff);
+	len = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0,
+			      (unsigned char *)buf, 0xffff);
+	
+	if (len < 0) {
+		WARN (_("Could not read pilot's Memo application block"));
+		WARN ("dlp_ReadAppBlock(...) = %d", len);
+		gnome_pilot_conduit_error (conduit,
+					   _("Could not read pilot's Memo application block"));
+		return -1;
+	}
+	unpack_MemoAppInfo (&(ctxt->ai), buf, len);
+	g_free (buf);
+	
+	lastDesktopUniqueID = 128;
+
+	check_for_slow_setting (conduit, ctxt);
+	if (ctxt->cfg->sync_type == GnomePilotConduitSyncTypeCopyToPilot
+	    || ctxt->cfg->sync_type == GnomePilotConduitSyncTypeCopyFromPilot)
+		ctxt->map->write_touched_only = TRUE;
+	
+	return 0;
+}
+
+static gint
+post_sync (GnomePilotConduit *conduit,
+	   GnomePilotDBInfo *dbi,
+	   EMemoConduitContext *ctxt)
+{
+	GList *changed;
+	gchar *filename, *change_id;
+	unsigned char *buf;
+	int dlpRetVal, len;
+
+	buf = (unsigned char*)g_malloc (0xffff);
+	
+	len = pack_MemoAppInfo (&(ctxt->ai), buf, 0xffff);
+	
+	dlpRetVal = dlp_WriteAppBlock (dbi->pilot_socket, dbi->db_handle, 
+			      (unsigned char *)buf, len);
+	
+	g_free (buf);
+			      
+	if (dlpRetVal < 0) {
+		WARN (_("Could not write pilot's Memo application block"));
+		WARN ("dlp_WriteAppBlock(...) = %d", dlpRetVal);
+		gnome_pilot_conduit_error (conduit,
+					   _("Could not write pilot's Memo application block"));
+		return -1;
+	}
+	
+
+	LOG (g_message ( "post_sync: Memo Conduit v.%s", CONDUIT_VERSION ));
+
+	g_free (ctxt->cfg->last_uri);
+	ctxt->cfg->last_uri = g_strdup (e_cal_get_uri (ctxt->client));
+	memoconduit_save_configuration (ctxt->cfg);
+	
+	filename = map_name (ctxt);
+	e_pilot_map_write (filename, ctxt->map);
+	g_free (filename);
+
+	/* FIX ME ugly hack - our changes musn't count, this does introduce
+	 * a race condition if anyone changes a record elsewhere during sycnc
+         */
+	change_id = g_strdup_printf ("pilot-sync-evolution-memo-%d", ctxt->cfg->pilot_id);
+	if (e_cal_get_changes (ctxt->client, change_id, &changed, NULL))
+		e_cal_free_change_list (changed);
+	g_free (change_id);
+	
+	LOG (g_message ( "---------------------------------------------------------\n" ));
+
+	return 0;
+}
+
+static gint
+set_pilot_id (GnomePilotConduitSyncAbs *conduit,
+	      EMemoLocalRecord *local,
+	      guint32 ID,
+	      EMemoConduitContext *ctxt)
+{
+	const char *uid;
+
+	LOG (g_message ( "set_pilot_id: setting to %d\n", ID ));
+	
+	e_cal_component_get_uid (local->comp, &uid);
+	e_pilot_map_insert (ctxt->map, ID, uid, FALSE);
+
+        return 0;
+}
+
+static gint
+set_status_cleared (GnomePilotConduitSyncAbs *conduit,
+		    EMemoLocalRecord *local,
+		    EMemoConduitContext *ctxt)
+{
+	const char *uid;
+	
+	LOG (g_message ( "set_status_cleared: clearing status\n" ));
+	
+	e_cal_component_get_uid (local->comp, &uid);
+	g_hash_table_remove (ctxt->changed_hash, uid);
+	
+        return 0;
+}
+
+static gint
+for_each (GnomePilotConduitSyncAbs *conduit,
+	  EMemoLocalRecord **local,
+	  EMemoConduitContext *ctxt)
+{
+	static GList *comps, *iterator;
+	static int count;
+
+	g_return_val_if_fail (local != NULL, -1);
+
+	if (*local == NULL) {
+		LOG (g_message ( "beginning for_each" ));
+
+		comps = ctxt->comps;
+		count = 0;
+		
+		if (comps != NULL) {
+			LOG (g_message ( "for_each: iterating over %d records", g_list_length (comps)));
+
+			*local = g_new0 (EMemoLocalRecord, 1);
+			LOG(fprintf(stderr, "for_each: calling local_record_from_comp\n"));
+			local_record_from_comp (*local, comps->data, ctxt);
+			LOG(fprintf(stderr, "for_each: calling g_list_prepend\n"));
+			g_list_prepend (ctxt->locals, *local);
+			LOG(fprintf(stderr, "for_each: setting iterator = comps\n"));
+			iterator = comps;
+		} else {
+			LOG (g_message ( "no events" ));
+			(*local) = NULL;
+			return 0;
+		}
+	} else {
+		count++;
+		LOG(fprintf(stderr, "for_each: calling g_list_next (else part)\n"));
+		if (g_list_next (iterator)) {
+			iterator = g_list_next (iterator);
+			LOG(fprintf(stderr, "for_each: creating EMemoLocalRecord\n"));
+			*local = g_new0 (EMemoLocalRecord, 1);
+			LOG(fprintf(stderr, "for_each: calling local_record_from_comp\n"));
+			local_record_from_comp (*local, iterator->data, ctxt);
+			LOG(fprintf(stderr, "for_each: calling g_list_prepend\n"));
+			g_list_prepend (ctxt->locals, *local);
+		} else {
+			LOG (g_message ( "for_each ending" ));
+
+			/* Tell the pilot the iteration is over */
+			*local = NULL;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static gint
+for_each_modified (GnomePilotConduitSyncAbs *conduit,
+		   EMemoLocalRecord **local,
+		   EMemoConduitContext *ctxt)
+{
+	static GList *iterator;
+	static int count;
+
+	g_return_val_if_fail (local != NULL, 0);
+
+	if (*local == NULL) {
+		LOG (g_message ( "for_each_modified beginning\n" ));
+		
+		iterator = ctxt->changed;
+		
+		count = 0;
+	
+		LOG (g_message ( "iterating over %d records", g_hash_table_size (ctxt->changed_hash) ));
+		
+		iterator = next_changed_item (ctxt, iterator);
+		if (iterator != NULL) {
+			ECalChange *ccc = iterator->data;
+			LOG(fprintf(stderr, "for_each_modified: creating EMemoLocalRecord\n"));
+			*local = g_new0 (EMemoLocalRecord, 1);
+			LOG(fprintf(stderr, "for_each_modified: calling local_record_from_comp\n"));
+			local_record_from_comp (*local, ccc->comp, ctxt);
+			LOG(fprintf(stderr, "for_each_modified: calling g_list_prepend\n"));
+			g_list_prepend (ctxt->locals, *local);
+		} else {
+			LOG (g_message ( "no events" ));
+
+			*local = NULL;
+		}
+	} else {
+		count++;
+		LOG(fprintf(stderr, "for_each_modified: calling g_list_next\n"));
+		iterator = g_list_next (iterator);
+		LOG(fprintf(stderr, "for_each_modified: calling next_changed_item\n"));
+		if (iterator && (iterator = next_changed_item (ctxt, iterator))) {
+			ECalChange *ccc = iterator->data;
+			LOG(fprintf(stderr, "for_each_modified: calling EMemoLocalRecord\n"));
+			*local = g_new0 (EMemoLocalRecord, 1);
+			LOG(fprintf(stderr, "for_each_modified: calling local_record_from_comp\n"));
+			local_record_from_comp (*local, ccc->comp, ctxt);
+			LOG(fprintf(stderr, "for_each_modified: calling g_list_prepend\n"));
+			g_list_prepend (ctxt->locals, *local);
+		} else {
+			LOG (g_message ( "for_each_modified ending" ));
+
+			/* Signal the iteration is over */
+			*local = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static gint
+compare (GnomePilotConduitSyncAbs *conduit,
+	 EMemoLocalRecord *local,
+	 GnomePilotRecord *remote,
+	 EMemoConduitContext *ctxt)
+{
+	/* used by the quick compare */
+	GnomePilotRecord local_pilot;
+	int retval = 0;
+
+	LOG (g_message ("compare: local=%s remote=%s...\n",
+			print_local (local), print_remote (remote)));
+
+	g_return_val_if_fail (local!=NULL,-1);
+	g_return_val_if_fail (remote!=NULL,-1);
+
+	local_pilot = local_record_to_pilot_record (local, ctxt);
+
+	if (remote->length != local_pilot.length
+	    || memcmp (local_pilot.record, remote->record, remote->length))
+		retval = 1;
+
+	if (retval == 0)
+		LOG (g_message ( "    equal" ));
+	else
+		LOG (g_message ( "    not equal" ));
+	
+	return retval;
+}
+
+static gint
+add_record (GnomePilotConduitSyncAbs *conduit,
+	    GnomePilotRecord *remote,
+	    EMemoConduitContext *ctxt)
+{
+	ECalComponent *comp;
+	char *uid;
+	int retval = 0;
+	
+	g_return_val_if_fail (remote != NULL, -1);
+
+	LOG (g_message ( "add_record: adding %s to desktop\n", print_remote (remote) ));
+
+	comp = comp_from_remote_record (conduit, remote, ctxt->default_comp, ctxt->timezone, &(ctxt->ai));
+
+	/* Give it a new UID otherwise it will be the uid of the default comp */
+	uid = e_cal_component_gen_uid ();
+	e_cal_component_set_uid (comp, uid);
+
+	if (!e_cal_create_object (ctxt->client, e_cal_component_get_icalcomponent (comp), NULL, NULL))
+		return -1;
+
+	e_pilot_map_insert (ctxt->map, remote->ID, uid, FALSE);
+
+	g_object_unref (comp);
+
+	return retval;
+}
+
+static gint
+replace_record (GnomePilotConduitSyncAbs *conduit,
+		EMemoLocalRecord *local,
+		GnomePilotRecord *remote,
+		EMemoConduitContext *ctxt)
+{
+	ECalComponent *new_comp;
+	int retval = 0;
+	
+	g_return_val_if_fail (remote != NULL, -1);
+
+	LOG (g_message ("replace_record: replace %s with %s\n",
+			print_local (local), print_remote (remote)));
+
+	new_comp = comp_from_remote_record (conduit, remote, local->comp, ctxt->timezone, &(ctxt->ai));
+	g_object_unref (local->comp);
+	local->comp = new_comp;
+
+	if (!e_cal_modify_object (ctxt->client, e_cal_component_get_icalcomponent (new_comp), 
+				       CALOBJ_MOD_ALL, NULL))
+		return -1;
+
+	return retval;
+}
+
+static gint
+delete_record (GnomePilotConduitSyncAbs *conduit,
+	       EMemoLocalRecord *local,
+	       EMemoConduitContext *ctxt)
+{
+	const char *uid;
+
+	g_return_val_if_fail (local != NULL, -1);
+	g_return_val_if_fail (local->comp != NULL, -1);
+
+	e_cal_component_get_uid (local->comp, &uid);
+
+	LOG (g_message ( "delete_record: deleting %s", uid ));
+
+	e_pilot_map_remove_by_uid (ctxt->map, uid);
+	/* FIXME Error handling */
+	e_cal_remove_object (ctxt->client, uid, NULL);
+	
+        return 0;
+}
+
+static gint
+archive_record (GnomePilotConduitSyncAbs *conduit,
+		EMemoLocalRecord *local,
+		gboolean archive,
+		EMemoConduitContext *ctxt)
+{
+	const char *uid;
+	int retval = 0;
+	
+	g_return_val_if_fail (local != NULL, -1);
+
+	LOG (g_message ( "archive_record: %s\n", archive ? "yes" : "no" ));
+
+	e_cal_component_get_uid (local->comp, &uid);
+	e_pilot_map_insert (ctxt->map, local->local.ID, uid, archive);
+	
+        return retval;
+}
+
+static gint
+match (GnomePilotConduitSyncAbs *conduit,
+       GnomePilotRecord *remote,
+       EMemoLocalRecord **local,
+       EMemoConduitContext *ctxt)
+{
+	const char *uid;
+	
+	LOG (g_message ("match: looking for local copy of %s\n",
+			print_remote (remote)));	
+	
+	g_return_val_if_fail (local != NULL, -1);
+	g_return_val_if_fail (remote != NULL, -1);
+
+	*local = NULL;
+	uid = e_pilot_map_lookup_uid (ctxt->map, remote->ID, TRUE);
+	
+	if (!uid)
+		return 0;
+
+	LOG (g_message ( "  matched\n" ));
+	
+	*local = g_new0 (EMemoLocalRecord, 1);
+	local_record_from_uid (*local, uid, ctxt);
+	
+	return 0;
+}
+
+static gint
+free_match (GnomePilotConduitSyncAbs *conduit,
+	    EMemoLocalRecord *local,
+	    EMemoConduitContext *ctxt)
+{
+	LOG (g_message ( "free_match: freeing\n" ));
+
+	g_return_val_if_fail (local != NULL, -1);
+
+	memoconduit_destroy_record (local);
+
+	return 0;
+}
+
+static gint
+prepare (GnomePilotConduitSyncAbs *conduit,
+	 EMemoLocalRecord *local,
+	 GnomePilotRecord *remote,
+	 EMemoConduitContext *ctxt)
+{
+	LOG (g_message ( "prepare: encoding local %s\n", print_local (local) ));
+
+	*remote = local_record_to_pilot_record (local, ctxt);
+
+	return 0;
+}
+
+/* Pilot Settings Callbacks */
+static void
+fill_widgets (EMemoConduitContext *ctxt)
+{
+	if (ctxt->cfg->source)
+		e_pilot_settings_set_source (E_PILOT_SETTINGS (ctxt->ps), 
+					     ctxt->cfg->source);
+	e_pilot_settings_set_secret (E_PILOT_SETTINGS (ctxt->ps),
+				     ctxt->cfg->secret);
+}
+
+static gint
+create_settings_window (GnomePilotConduit *conduit,
+			GtkWidget *parent,
+			EMemoConduitContext *ctxt)
+{
+	LOG (g_message ( "create_settings_window" ));
+	
+	if (!ctxt->cfg->source_list)	
+		return -1;
+
+	ctxt->ps = e_pilot_settings_new (ctxt->cfg->source_list);
+
+	gtk_container_add (GTK_CONTAINER (parent), ctxt->ps);
+	gtk_widget_show (ctxt->ps);
+
+	fill_widgets (ctxt);
+	
+	return 0;
+}
+
+static void
+display_settings (GnomePilotConduit *conduit, EMemoConduitContext *ctxt)
+{
+	LOG (g_message ( "display_settings" ));
+	
+	fill_widgets (ctxt);
+}
+
+static void
+save_settings    (GnomePilotConduit *conduit, EMemoConduitContext *ctxt)
+{
+	LOG (g_message ( "save_settings" ));
+
+	if (ctxt->new_cfg->source)
+		g_object_unref (ctxt->new_cfg->source);
+	ctxt->new_cfg->source = e_pilot_settings_get_source (E_PILOT_SETTINGS (ctxt->ps));
+	g_object_ref (ctxt->new_cfg->source);
+	ctxt->new_cfg->secret = e_pilot_settings_get_secret (E_PILOT_SETTINGS (ctxt->ps));
+	
+	memoconduit_save_configuration (ctxt->new_cfg);
+}
+
+static void
+revert_settings  (GnomePilotConduit *conduit, EMemoConduitContext *ctxt)
+{
+	LOG (g_message ( "revert_settings" ));
+
+	memoconduit_save_configuration (ctxt->cfg);
+	memoconduit_destroy_configuration (ctxt->new_cfg);
+	ctxt->new_cfg = memoconduit_dupe_configuration (ctxt->cfg);
+}
+
+GnomePilotConduit *
+conduit_get_gpilot_conduit (guint32 pilot_id)
+{
+	GtkObject *retval;
+	EMemoConduitContext *ctxt;
+
+	LOG (g_message ( "in memo's conduit_get_gpilot_conduit\n" ));
+
+	retval = gnome_pilot_conduit_sync_abs_new ("MemoDB", 0x6D656D6F);
+	g_assert (retval != NULL);
+	
+	ctxt = e_memo_context_new (pilot_id);
+	gtk_object_set_data (GTK_OBJECT (retval), "memoconduit_context", ctxt);
+
+	gtk_signal_connect (retval, "pre_sync", (GtkSignalFunc) pre_sync, ctxt);
+	gtk_signal_connect (retval, "post_sync", (GtkSignalFunc) post_sync, ctxt);
+
+  	gtk_signal_connect (retval, "set_pilot_id", (GtkSignalFunc) set_pilot_id, ctxt);
+  	gtk_signal_connect (retval, "set_status_cleared", (GtkSignalFunc) set_status_cleared, ctxt);
+
+  	gtk_signal_connect (retval, "for_each", (GtkSignalFunc) for_each, ctxt);
+  	gtk_signal_connect (retval, "for_each_modified", (GtkSignalFunc) for_each_modified, ctxt);
+  	gtk_signal_connect (retval, "compare", (GtkSignalFunc) compare, ctxt);
+
+  	gtk_signal_connect (retval, "add_record", (GtkSignalFunc) add_record, ctxt);
+  	gtk_signal_connect (retval, "replace_record", (GtkSignalFunc) replace_record, ctxt);
+  	gtk_signal_connect (retval, "delete_record", (GtkSignalFunc) delete_record, ctxt);
+  	gtk_signal_connect (retval, "archive_record", (GtkSignalFunc) archive_record, ctxt);
+
+  	gtk_signal_connect (retval, "match", (GtkSignalFunc) match, ctxt);
+  	gtk_signal_connect (retval, "free_match", (GtkSignalFunc) free_match, ctxt);
+
+  	gtk_signal_connect (retval, "prepare", (GtkSignalFunc) prepare, ctxt);
+
+	/* Gui Settings */
+	gtk_signal_connect (retval, "create_settings_window", (GtkSignalFunc) create_settings_window, ctxt);
+	gtk_signal_connect (retval, "display_settings", (GtkSignalFunc) display_settings, ctxt);
+	gtk_signal_connect (retval, "save_settings", (GtkSignalFunc) save_settings, ctxt);
+	gtk_signal_connect (retval, "revert_settings", (GtkSignalFunc) revert_settings, ctxt);
+
+	return GNOME_PILOT_CONDUIT (retval);
+}
+
+void
+conduit_destroy_gpilot_conduit (GnomePilotConduit *conduit)
+{ 
+	GtkObject *obj = GTK_OBJECT (conduit);
+	EMemoConduitContext *ctxt;
+	
+	ctxt = gtk_object_get_data (obj, "memoconduit_context");
+	e_memo_context_destroy (ctxt);
+
+	gtk_object_destroy (obj);
+}
Index: calendar/gui/e-cal-component-memo-preview.c
===================================================================
RCS file: calendar/gui/e-cal-component-memo-preview.c
diff -N calendar/gui/e-cal-component-memo-preview.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-cal-component-memo-preview.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,374 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-tasks.c
+ *
+ * Copyright (C) 2001-2003  Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Federico Mena Quintero <federico ximian com>
+ *	    Damon Chaplin <damon ximian com>
+ *          Rodrigo Moya <rodrigo ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnome.h>
+#include <gtk/gtk.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <libecal/e-cal-time-util.h>
+#include <libedataserver/e-categories.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
+#include <e-util/e-time-utils.h>
+#include <e-util/e-categories-config.h>
+#include "calendar-config.h"
+#include "e-cal-component-memo-preview.h"
+
+struct _ECalComponentMemoPreviewPrivate {
+	GtkWidget *html;
+
+	icaltimezone *zone;
+};
+
+G_DEFINE_TYPE (ECalComponentMemoPreview, e_cal_component_memo_preview, GTK_TYPE_TABLE);
+
+
+static void
+on_link_clicked (GtkHTML *html, const char *url, gpointer data)
+{
+        GError *err = NULL;
+
+        gnome_url_show (url, &err);
+
+	if (err) {
+		g_warning ("gnome_url_show: %s", err->message);
+                g_error_free (err);
+        }
+}
+
+static void
+on_url_cb (GtkHTML *html, const char *url, gpointer data)
+{
+#if 0
+	char *msg;
+	ECalComponentMemoPreview *preview = data;
+
+	if (url && *url) {
+		msg = g_strdup_printf (_("Click to open %s"), url);
+		e_calendar_table_set_status_message (e_tasks_get_calendar_table (tasks), msg);
+		g_free (msg);
+	} else
+		e_calendar_table_set_status_message (e_tasks_get_calendar_table (tasks), NULL);
+#endif
+}
+
+/* Callback used when the user selects a URL in the HTML widget */
+static void
+url_requested_cb (GtkHTML *html, const char *url, GtkHTMLStream *stream, gpointer data)
+{
+	if (!strncmp ("file:///", url, strlen ("file:///"))) {
+		GnomeVFSHandle *handle;
+		GnomeVFSResult result;
+		char buffer[4096];
+
+		if (gnome_vfs_open (&handle, url, GNOME_VFS_OPEN_READ) == GNOME_VFS_OK) {
+			do {
+				GnomeVFSFileSize bread;
+
+				result = gnome_vfs_read (handle, buffer, sizeof (buffer), &bread);
+				if (result == GNOME_VFS_OK)
+					gtk_html_stream_write (stream, buffer, bread);
+			} while (result == GNOME_VFS_OK);
+
+			gnome_vfs_close (handle);
+		}
+	}
+}
+
+/* Converts a time_t to a string, relative to the specified timezone */
+static char *
+timet_to_str_with_zone (ECalComponentDateTime *dt, ECal *ecal, icaltimezone *default_zone)
+{
+	struct icaltimetype itt;
+	icaltimezone *zone;
+        struct tm tm;
+        char buf[256];                                                                                              
+
+	if (dt->tzid) {
+		/* If we can't find the zone, we'll guess its "local" */
+		if (!e_cal_get_timezone (ecal, dt->tzid, &zone, NULL))
+			zone = NULL;
+	} else if (dt->value->is_utc) {
+		zone = icaltimezone_get_utc_timezone ();
+	} else {
+		zone = NULL;
+	}
+	
+	
+	itt = *dt->value;
+	if (zone)
+		icaltimezone_convert_time (&itt, zone, default_zone);
+        tm = icaltimetype_to_tm (&itt);
+                                                                                              
+        e_time_format_date_and_time (&tm, calendar_config_get_24_hour_format (),
+                                     FALSE, FALSE, buf, sizeof (buf));
+
+	return g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+}
+
+static void
+write_html (GtkHTMLStream *stream, ECal *ecal, ECalComponent *comp, icaltimezone *default_zone)
+{
+	ECalComponentText text;
+	ECalComponentDateTime dt;
+	gchar *str;
+	GSList *l;
+	icalproperty_status status;
+	const char *location;
+	int *priority_value;
+	gboolean one_added = FALSE;
+
+	g_return_if_fail (E_IS_CAL_COMPONENT (comp));
+
+	gtk_html_stream_printf (stream,
+				"<HTML><BODY>");
+
+	/* write icons for the categories */
+	e_cal_component_get_categories_list (comp, &l);
+	if (l) {
+		GSList *node;
+		GString *str = g_string_new ("");
+		
+		
+		gtk_html_stream_printf(stream, "<H3>Categories: ");
+
+		for (node = l; node != NULL; node = node->next) {
+			const char *icon_file;
+
+			icon_file = e_categories_get_icon_file_for ((const char *) node->data);
+			if (icon_file && g_file_test(icon_file, G_FILE_TEST_EXISTS)) {
+				gtk_html_stream_printf (stream, "<IMG ALT=\"%s\" SRC=\"file://%s\">",
+							(const char *) node->data, icon_file);
+				one_added = TRUE;
+			}
+			else{
+				if(one_added == FALSE){
+					g_string_append_printf (str, "%s", (const char *) node->data);
+					one_added = TRUE;
+				}
+				else{
+					g_string_append_printf (str, ", %s", (const char *) node->data);
+				}
+			}
+		}
+		
+		gtk_html_stream_printf(stream, str->str);
+		
+		gtk_html_stream_printf(stream, "</H3>");
+
+		e_cal_component_free_categories_list (l);
+	}
+
+	/* Start table */
+	gtk_html_stream_printf (stream, "<TABLE BORDER=\"0\" WIDTH=\"80%%\">"
+				"<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" WIDTH=\"15%%\"></TD></TR>");	
+
+
+	/* write description and URL */
+	gtk_html_stream_printf (stream, "<TR><TD COLSPAN=\"2\"><HR></TD></TR>");
+
+	e_cal_component_get_description_list (comp, &l);
+	if (l) {
+		GSList *node;
+
+		gtk_html_stream_printf (stream, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\"><B>%s</B></TD>", _("Memo:"));
+
+		gtk_html_stream_printf (stream, "<TD>");
+
+		for (node = l; node != NULL; node = node->next) {
+			gint i, j;
+			GString *str = g_string_new ("");
+
+			text = * (ECalComponentText *) node->data;
+			for (i = 0, j=0; i < strlen (text.value ? text.value : 0); i++, j++) {
+				if (text.value[i] == '\n'){
+					str = g_string_append (str, "<BR>");
+				}
+				else if (text.value[i] == '<')
+					str = g_string_append (str, "&lt;");
+				else if (text.value[i] == '>')
+					str = g_string_append (str, "&gt;");
+				else
+					str = g_string_append_c (str, text.value[i]);
+			}
+
+			gtk_html_stream_printf (stream, str->str);
+			g_string_free (str, TRUE);
+		}
+
+		gtk_html_stream_printf (stream, "</TD></TR>");
+
+		e_cal_component_free_text_list (l);
+	}
+
+	/* URL */
+	e_cal_component_get_url (comp, (const char **) &str);
+	if (str) {
+		gtk_html_stream_printf (stream, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\"><B>%s</B></TD>", _("Web Page:"));
+		gtk_html_stream_printf (stream, "<TD><A HREF=\"%s\">%s</A></TD></TR>", str, str);
+	}
+	
+	gtk_html_stream_printf (stream, "</TABLE>");
+
+	/* close document */
+	gtk_html_stream_printf (stream, "</BODY></HTML>");
+}
+
+static void
+e_cal_component_memo_preview_init (ECalComponentMemoPreview *preview)
+{
+	ECalComponentMemoPreviewPrivate *priv;
+	GtkWidget *scroll;
+	
+	priv = g_new0 (ECalComponentMemoPreviewPrivate, 1);
+	preview->priv = priv;
+
+	priv->html = gtk_html_new ();
+	gtk_html_set_default_content_type (GTK_HTML (priv->html), "charset=utf-8");
+	gtk_html_load_empty (GTK_HTML (priv->html));
+
+	g_signal_connect (G_OBJECT (priv->html), "url_requested",
+			  G_CALLBACK (url_requested_cb), NULL);
+	g_signal_connect (G_OBJECT (priv->html), "link_clicked",
+			  G_CALLBACK (on_link_clicked), preview);
+	g_signal_connect (G_OBJECT (priv->html), "on_url",
+			  G_CALLBACK (on_url_cb), preview);
+
+	scroll = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
+
+	gtk_container_add (GTK_CONTAINER (scroll), priv->html);
+	gtk_container_add (GTK_CONTAINER (preview), scroll);
+	gtk_widget_show_all (scroll);
+	
+	priv->zone = icaltimezone_get_utc_timezone ();
+}
+
+static void
+e_cal_component_memo_preview_destroy (GtkObject *object)
+{
+	ECalComponentMemoPreview *preview;
+	ECalComponentMemoPreviewPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (E_IS_CAL_COMPONENT_MEMO_PREVIEW (object));
+
+	preview = E_CAL_COMPONENT_MEMO_PREVIEW (object);
+	priv = preview->priv;
+
+	if (priv) {
+
+		g_free (priv);
+		preview->priv = NULL;
+	}
+
+	if (GTK_OBJECT_CLASS (e_cal_component_memo_preview_parent_class)->destroy)
+		(* GTK_OBJECT_CLASS (e_cal_component_memo_preview_parent_class)->destroy) (object);
+}
+
+static void
+e_cal_component_memo_preview_class_init (ECalComponentMemoPreviewClass *klass)
+{
+	GtkObjectClass *object_class;
+	
+	object_class = (GtkObjectClass *) klass;
+	
+	object_class->destroy = e_cal_component_memo_preview_destroy;
+}
+
+GtkWidget *
+e_cal_component_memo_preview_new (void)
+{
+	ECalComponentMemoPreview *preview;
+
+	preview = g_object_new (e_cal_component_memo_preview_get_type (), NULL);
+
+	return GTK_WIDGET (preview);
+}
+
+icaltimezone *
+e_cal_component_memo_preview_get_default_timezone (ECalComponentMemoPreview *preview)
+{
+	ECalComponentMemoPreviewPrivate *priv;
+	
+	g_return_val_if_fail (preview != NULL, NULL);
+	g_return_val_if_fail (E_IS_CAL_COMPONENT_MEMO_PREVIEW (preview), NULL);
+
+	priv = preview->priv;
+
+	return priv->zone;
+}
+
+void
+e_cal_component_memo_preview_set_default_timezone (ECalComponentMemoPreview *preview, icaltimezone *zone)
+{
+	ECalComponentMemoPreviewPrivate *priv;
+	
+	g_return_if_fail (preview != NULL);
+	g_return_if_fail (E_IS_CAL_COMPONENT_MEMO_PREVIEW (preview));
+	g_return_if_fail (zone != NULL);
+
+	priv = preview->priv;
+	
+	priv->zone = zone;
+}
+
+void
+e_cal_component_memo_preview_display (ECalComponentMemoPreview *preview, ECal *ecal, ECalComponent *comp)
+{
+	ECalComponentMemoPreviewPrivate *priv;
+	GtkHTMLStream *stream;
+
+	g_return_if_fail (preview != NULL);
+	g_return_if_fail (E_IS_CAL_COMPONENT_MEMO_PREVIEW (preview));
+	g_return_if_fail (comp != NULL);
+	g_return_if_fail (E_IS_CAL_COMPONENT (comp));
+
+	priv = preview->priv;
+	
+	stream = gtk_html_begin (GTK_HTML (priv->html));
+	write_html (stream, ecal, comp, priv->zone);
+	gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
+}
+
+void
+e_cal_component_memo_preview_clear (ECalComponentMemoPreview *preview)
+{
+	ECalComponentMemoPreviewPrivate *priv;
+
+	g_return_if_fail (preview != NULL);
+	g_return_if_fail (E_IS_CAL_COMPONENT_MEMO_PREVIEW (preview));
+	
+	priv = preview->priv;
+	
+	gtk_html_load_empty (GTK_HTML (priv->html));
+}
+
Index: calendar/gui/e-cal-component-memo-preview.h
===================================================================
RCS file: calendar/gui/e-cal-component-memo-preview.h
diff -N calendar/gui/e-cal-component-memo-preview.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-cal-component-memo-preview.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,66 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-cal-component-memo-preview.h
+ *
+ * Copyright (C) 2004  Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Federico Mena Quintero <federico ximian com>
+ *	    Damon Chaplin <damon ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifndef _E_CAL_COMPONENT_MEMO_PREVIEW_H_
+#define _E_CAL_COMPONENT_MEMO_PREVIEW_H_
+
+#include <gtk/gtktable.h>
+#include <libecal/e-cal.h>
+
+#define E_TYPE_CAL_COMPONENT_MEMO_PREVIEW            (e_cal_component_memo_preview_get_type ())
+#define E_CAL_COMPONENT_MEMO_PREVIEW(obj)            (GTK_CHECK_CAST ((obj), E_TYPE_CAL_COMPONENT_MEMO_PREVIEW, ECalComponentMemoPreview))
+#define E_CAL_COMPONENT_MEMO_PREVIEW_CLASS(klass)    (GTK_CHECK_CAST_CLASS ((klass), E_TYPE_CAL_COMPONENT_MEMO_PREVIEW, \
+				                 ECalComponentMemoPreviewClass))
+#define E_IS_CAL_COMPONENT_MEMO_PREVIEW(obj)         (GTK_CHECK_TYPE ((obj), E_TYPE_CAL_COMPONENT_MEMO_PREVIEW))
+#define E_IS_CAL_COMPONENT_MEMO_PREVIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_COMPONENT_MEMO_PREVIEW))
+
+typedef struct _ECalComponentMemoPreview	ECalComponentMemoPreview;
+typedef struct _ECalComponentMemoPreviewClass	ECalComponentMemoPreviewClass;
+typedef struct _ECalComponentMemoPreviewPrivate	ECalComponentMemoPreviewPrivate;
+
+struct _ECalComponentMemoPreview {
+	GtkTable table;
+
+	/* Private data */
+	ECalComponentMemoPreviewPrivate *priv;
+};
+
+struct _ECalComponentMemoPreviewClass {
+	GtkTableClass parent_class;
+
+	/* Notification signals */
+	void (* selection_changed) (ECalComponentMemoPreview *preview, int n_selected);
+};
+
+
+GtkType    e_cal_component_memo_preview_get_type        (void);
+GtkWidget *e_cal_component_memo_preview_new             (void);
+
+icaltimezone *e_cal_component_memo_preview_get_default_timezone (ECalComponentMemoPreview *preview);
+void e_cal_component_memo_preview_set_default_timezone (ECalComponentMemoPreview *preview, icaltimezone *zone);
+
+void e_cal_component_memo_preview_display             (ECalComponentMemoPreview *preview, ECal *ecal, ECalComponent *comp);
+void e_cal_component_memo_preview_clear             (ECalComponentMemoPreview *preview);
+
+#endif /* _E_CAL_COMPONENT_MEMO_PREVIEW_H_ */
Index: calendar/gui/e-cal-model-memos.c
===================================================================
RCS file: calendar/gui/e-cal-model-memos.c
diff -N calendar/gui/e-cal-model-memos.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-cal-model-memos.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,259 @@
+/* Evolution memos - Data model for ETable
+ *
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
+ *
+ * Authors: Rodrigo Moya <rodrigo ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <libgnome/gnome-i18n.h>
+#include "e-cal-model-memos.h"
+#include "e-cell-date-edit-text.h"
+#include "misc.h"
+
+#define d(x) (x)
+
+struct _ECalModelMemosPrivate {
+};
+
+static void e_cal_model_memos_finalize (GObject *object);
+
+static int ecmm_column_count (ETableModel *etm);
+static void *ecmm_value_at (ETableModel *etm, int col, int row);
+static void ecmm_set_value_at (ETableModel *etm, int col, int row, const void *value);
+static gboolean ecmm_is_cell_editable (ETableModel *etm, int col, int row);
+static void *ecmm_duplicate_value (ETableModel *etm, int col, const void *value);
+static void ecmm_free_value (ETableModel *etm, int col, void *value);
+static void *ecmm_initialize_value (ETableModel *etm, int col);
+static gboolean ecmm_value_is_empty (ETableModel *etm, int col, const void *value);
+static char *ecmm_value_to_string (ETableModel *etm, int col, const void *value);
+
+static void ecmm_fill_component_from_model (ECalModel *model, ECalModelComponent *comp_data,
+					    ETableModel *source_model, gint row);
+
+G_DEFINE_TYPE (ECalModelMemos, e_cal_model_memos, E_TYPE_CAL_MODEL);
+
+static void
+e_cal_model_memos_class_init (ECalModelMemosClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass);
+	ECalModelClass *model_class = E_CAL_MODEL_CLASS (klass);
+
+	object_class->finalize = e_cal_model_memos_finalize;
+
+	etm_class->column_count = ecmm_column_count;
+	etm_class->value_at = ecmm_value_at;
+	etm_class->set_value_at = ecmm_set_value_at;
+	etm_class->is_cell_editable = ecmm_is_cell_editable;
+	etm_class->duplicate_value = ecmm_duplicate_value;
+	etm_class->free_value = ecmm_free_value;
+	etm_class->initialize_value = ecmm_initialize_value;
+	etm_class->value_is_empty = ecmm_value_is_empty;
+	etm_class->value_to_string = ecmm_value_to_string;
+
+	model_class->fill_component_from_model = ecmm_fill_component_from_model;
+}
+
+static void
+e_cal_model_memos_init (ECalModelMemos *model)
+{
+	ECalModelMemosPrivate *priv;
+
+	priv = g_new0 (ECalModelMemosPrivate, 1);
+	model->priv = priv;
+
+	e_cal_model_set_component_kind (E_CAL_MODEL (model), ICAL_VJOURNAL_COMPONENT);
+}
+
+static void
+e_cal_model_memos_finalize (GObject *object)
+{
+	ECalModelMemosPrivate *priv;
+	ECalModelMemos *model = (ECalModelMemos *) object;
+
+	g_return_if_fail (E_IS_CAL_MODEL_MEMOS (model));
+
+	priv = model->priv;
+	if (priv) {
+		g_free (priv);
+		model->priv = NULL;
+	}
+
+	if (G_OBJECT_CLASS (e_cal_model_memos_parent_class)->finalize)
+		G_OBJECT_CLASS (e_cal_model_memos_parent_class)->finalize (object);
+}
+
+/* ETableModel methods */
+static int
+ecmm_column_count (ETableModel *etm)
+{
+	return E_CAL_MODEL_MEMOS_FIELD_LAST;
+}
+
+static void *
+ecmm_value_at (ETableModel *etm, int col, int row)
+{
+	ECalModelComponent *comp_data;
+	ECalModelMemosPrivate *priv;
+	ECalModelMemos *model = (ECalModelMemos *) etm;
+
+	g_return_val_if_fail (E_IS_CAL_MODEL_MEMOS (model), NULL);
+
+	priv = model->priv;
+
+	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST, NULL);
+	g_return_val_if_fail (row >= 0 && row < e_table_model_row_count (etm), NULL);
+
+	if (col < E_CAL_MODEL_FIELD_LAST)
+		return E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->value_at (etm, col, row);
+
+	comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
+	if (!comp_data)
+		return "";
+
+	return "";
+}
+
+
+static void
+ecmm_set_value_at (ETableModel *etm, int col, int row, const void *value)
+{
+	ECalModelComponent *comp_data;
+	ECalModelMemos *model = (ECalModelMemos *) etm;
+
+	g_return_if_fail (E_IS_CAL_MODEL_MEMOS (model));
+	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST);
+	g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm));
+
+	if (col < E_CAL_MODEL_FIELD_LAST) {
+		E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->set_value_at (etm, col, row, value);
+		return;
+	}
+
+	comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
+	if (!comp_data){
+		g_warning("couldn't get component data: row == %d", row);
+		return;
+	}
+
+	/* TODO ask about mod type */
+	if (!e_cal_modify_object (comp_data->client, comp_data->icalcomp, CALOBJ_MOD_ALL, NULL)) {
+		g_warning (G_STRLOC ": Could not modify the object!");
+		
+		/* TODO Show error dialog */
+	}
+}
+
+static gboolean
+ecmm_is_cell_editable (ETableModel *etm, int col, int row)
+{
+	ECalModelMemos *model = (ECalModelMemos *) etm;
+	gboolean retval = FALSE;
+
+	g_return_val_if_fail (E_IS_CAL_MODEL_MEMOS (model), FALSE);
+	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST, FALSE);
+	g_return_val_if_fail (row >= -1 || (row >= 0 && row < e_table_model_row_count (etm)), FALSE);
+
+	if(col == E_CAL_MODEL_FIELD_SUMMARY)
+		retval = FALSE;
+	else if (col < E_CAL_MODEL_FIELD_LAST)
+		retval = E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->is_cell_editable (etm, col, row);
+
+	return retval;
+}
+
+static void *
+ecmm_duplicate_value (ETableModel *etm, int col, const void *value)
+{
+	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST, NULL);
+
+	if (col < E_CAL_MODEL_FIELD_LAST)
+		return E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->duplicate_value (etm, col, value);
+
+	return NULL;
+}
+
+static void
+ecmm_free_value (ETableModel *etm, int col, void *value)
+{
+	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST);
+
+	if (col < E_CAL_MODEL_FIELD_LAST) {
+		E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->free_value (etm, col, value);
+		return;
+	}
+}
+
+static void *
+ecmm_initialize_value (ETableModel *etm, int col)
+{
+	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST, NULL);
+
+	if (col < E_CAL_MODEL_FIELD_LAST)
+		return E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->initialize_value (etm, col);
+
+	return NULL;
+}
+
+static gboolean
+ecmm_value_is_empty (ETableModel *etm, int col, const void *value)
+{
+	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST, TRUE);
+
+	if (col < E_CAL_MODEL_FIELD_LAST)
+		return E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->value_is_empty (etm, col, value);
+
+	return TRUE;
+}
+
+static char *
+ecmm_value_to_string (ETableModel *etm, int col, const void *value)
+{
+	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST, g_strdup (""));
+
+	if (col < E_CAL_MODEL_FIELD_LAST)
+		return E_TABLE_MODEL_CLASS (e_cal_model_memos_parent_class)->value_to_string (etm, col, value);
+
+	return g_strdup ("");
+}
+
+/* ECalModel class methods */
+
+static void
+ecmm_fill_component_from_model (ECalModel *model, ECalModelComponent *comp_data,
+				ETableModel *source_model, gint row)
+{
+	g_return_if_fail (E_IS_CAL_MODEL_MEMOS (model));
+	g_return_if_fail (comp_data != NULL);
+	g_return_if_fail (E_IS_TABLE_MODEL (source_model));
+
+}
+
+/**
+ * e_cal_model_memos_new
+ */
+ECalModelMemos *
+e_cal_model_memos_new (void)
+{
+	return g_object_new (E_TYPE_CAL_MODEL_MEMOS, NULL);
+}
Index: calendar/gui/e-cal-model-memos.h
===================================================================
RCS file: calendar/gui/e-cal-model-memos.h
diff -N calendar/gui/e-cal-model-memos.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-cal-model-memos.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,59 @@
+/* Evolution memo - Data model for ETable
+ *
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2000 Ximian, Inc.
+ *
+ * Authors: Rodrigo Moya <rodrigo ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef E_CAL_MODEL_MEMOS_H
+#define E_CAL_MODEL_MEMOS_H
+
+#include "e-cal-model.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_MODEL_MEMOS            (e_cal_model_memos_get_type ())
+#define E_CAL_MODEL_MEMOS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_MODEL_MEMOS, ECalModelMemo))
+#define E_CAL_MODEL_MEMOS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_MODEL_MEMOS, ECalModelMemoClass))
+#define E_IS_CAL_MODEL_MEMOS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_MODEL_MEMOS))
+#define E_IS_CAL_MODEL_MEMOS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_MODEL_MEMOS))
+
+typedef struct _ECalModelMemosPrivate ECalModelMemosPrivate;
+
+typedef enum {
+	/* If you add new items here or reorder them, you have to update the
+	   .etspec files for the tables using this model */
+	E_CAL_MODEL_MEMOS_FIELD_LAST = E_CAL_MODEL_FIELD_LAST
+
+} ECalModelMemoField;
+
+typedef struct {
+	ECalModel model;
+	ECalModelMemosPrivate *priv;
+} ECalModelMemos;
+
+typedef struct {
+	ECalModelClass parent_class;
+} ECalModelMemosClass;
+
+GType          e_cal_model_memos_get_type (void);
+ECalModelMemos *e_cal_model_memos_new (void);
+
+G_END_DECLS
+
+#endif
Index: calendar/gui/e-memo-table-config.c
===================================================================
RCS file: calendar/gui/e-memo-table-config.c
diff -N calendar/gui/e-memo-table-config.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memo-table-config.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Author : 
+ *  JP Rosevear <jpr ximian com>
+ *  Nathan Owens <pianocomp81 yahoo com>
+ *
+ * Copyright 2003, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of version 2 of the GNU General Public 
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "calendar-config.h"
+#include "e-memo-table-config.h"
+
+struct _EMemoTableConfigPrivate {
+	EMemoTable *table;
+	
+	GList *notifications;
+};
+
+G_DEFINE_TYPE (EMemoTableConfig, e_memo_table_config, G_TYPE_OBJECT);
+
+/* Property IDs */
+enum props {
+	PROP_0,
+	PROP_TABLE
+};
+
+static void
+e_memo_table_config_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	EMemoTableConfig *table_config;
+	EMemoTableConfigPrivate *priv;
+
+	table_config = E_MEMO_TABLE_CONFIG (object);
+	priv = table_config->priv;
+	
+	switch (property_id) {
+	case PROP_TABLE:
+		e_memo_table_config_set_table (table_config, g_value_get_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+static void
+e_memo_table_config_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	EMemoTableConfig *table_config;
+	EMemoTableConfigPrivate *priv;
+
+	table_config = E_MEMO_TABLE_CONFIG (object);
+	priv = table_config->priv;
+	
+	switch (property_id) {
+	case PROP_TABLE:
+		g_value_set_object (value, e_memo_table_config_get_table (table_config));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+static void
+e_memo_table_config_dispose (GObject *object)
+{
+	EMemoTableConfig *table_config = E_MEMO_TABLE_CONFIG (object);
+	EMemoTableConfigPrivate *priv;
+	
+	priv = table_config->priv;
+
+	e_memo_table_config_set_table (table_config, NULL);
+	
+	if (G_OBJECT_CLASS (e_memo_table_config_parent_class)->dispose)
+		G_OBJECT_CLASS (e_memo_table_config_parent_class)->dispose (object);
+}
+
+static void
+e_memo_table_config_finalize (GObject *object)
+{
+	EMemoTableConfig *table_config = E_MEMO_TABLE_CONFIG (object);
+	EMemoTableConfigPrivate *priv;
+	
+	priv = table_config->priv;
+
+	g_free (priv);
+	
+	if (G_OBJECT_CLASS (e_memo_table_config_parent_class)->finalize)
+		G_OBJECT_CLASS (e_memo_table_config_parent_class)->finalize (object);
+}
+
+static void
+e_memo_table_config_class_init (EMemoTableConfigClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GParamSpec *spec;
+
+	/* Method override */
+	gobject_class->set_property = e_memo_table_config_set_property;
+	gobject_class->get_property = e_memo_table_config_get_property;
+	gobject_class->dispose = e_memo_table_config_dispose;
+	gobject_class->finalize = e_memo_table_config_finalize;
+
+	spec = g_param_spec_object ("table", NULL, NULL, e_memo_table_get_type (),
+				    G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
+	g_object_class_install_property (gobject_class, PROP_TABLE, spec);
+}
+
+static void
+e_memo_table_config_init (EMemoTableConfig *table_config)
+{
+	table_config->priv = g_new0 (EMemoTableConfigPrivate, 1);
+
+}
+
+EMemoTableConfig *
+e_memo_table_config_new (EMemoTable *table)
+{
+	EMemoTableConfig *table_config;
+	
+	table_config = g_object_new (e_memo_table_config_get_type (), "table", table, NULL);
+
+	return table_config;
+}
+
+EMemoTable *
+e_memo_table_config_get_table (EMemoTableConfig *table_config) 
+{
+	EMemoTableConfigPrivate *priv;
+
+	g_return_val_if_fail (table_config != NULL, NULL);
+	g_return_val_if_fail (E_IS_MEMO_TABLE_CONFIG (table_config), NULL);
+
+	priv = table_config->priv;
+	
+	return priv->table;
+}
+
+static void
+set_timezone (EMemoTable *table) 
+{
+	ECalModel *model;
+	icaltimezone *zone;
+	
+	zone = calendar_config_get_icaltimezone ();
+	model = e_memo_table_get_model (table);
+	if (model)
+		e_cal_model_set_timezone (model, zone);
+}
+
+static void
+timezone_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
+{
+	EMemoTableConfig *table_config = data;
+	EMemoTableConfigPrivate *priv;
+	
+	priv = table_config->priv;
+	
+	set_timezone (priv->table);
+}
+
+static void
+set_twentyfour_hour (EMemoTable *table) 
+{
+	ECalModel *model;
+	gboolean use_24_hour;
+
+	use_24_hour = calendar_config_get_24_hour_format ();
+
+	model = e_memo_table_get_model (table);
+	if (model)
+		e_cal_model_set_use_24_hour_format (model, use_24_hour);
+}
+
+static void
+twentyfour_hour_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
+{
+	EMemoTableConfig *table_config = data;
+	EMemoTableConfigPrivate *priv;
+	
+	priv = table_config->priv;
+	
+	set_twentyfour_hour (priv->table);
+}
+
+void
+e_memo_table_config_set_table (EMemoTableConfig *table_config, EMemoTable *table) 
+{
+	EMemoTableConfigPrivate *priv;
+	guint not;
+	GList *l;
+	
+	g_return_if_fail (table_config != NULL);
+	g_return_if_fail (E_IS_MEMO_TABLE_CONFIG (table_config));
+
+	priv = table_config->priv;
+	
+	if (priv->table) {
+		g_object_unref (priv->table);
+		priv->table = NULL;
+	}
+	
+	for (l = priv->notifications; l; l = l->next)
+		calendar_config_remove_notification (GPOINTER_TO_UINT (l->data));
+
+	g_list_free (priv->notifications);
+	priv->notifications = NULL;
+
+	/* If the new view is NULL, return right now */
+	if (!table)
+		return;
+	
+	priv->table = g_object_ref (table);
+
+	/* Time zone */
+	set_timezone (table);
+	
+	not = calendar_config_add_notification_timezone (timezone_changed_cb, table_config);
+	priv->notifications = g_list_prepend (priv->notifications, GUINT_TO_POINTER (not));
+
+	/* 24 Hour format */
+	set_twentyfour_hour (table);	
+
+	not = calendar_config_add_notification_24_hour_format (twentyfour_hour_changed_cb, table_config);
+	priv->notifications = g_list_prepend (priv->notifications, GUINT_TO_POINTER (not));
+}
Index: calendar/gui/e-memo-table-config.h
===================================================================
RCS file: calendar/gui/e-memo-table-config.h
diff -N calendar/gui/e-memo-table-config.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memo-table-config.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Author : 
+ *  JP Rosevear <jpr ximian com>
+ *  Nathan Owens <pianocomp81 yahoo com>
+ *
+ * Copyright 2003, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of version 2 of the GNU General Public 
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef _E_MEMO_TABLE_CONFIG_H_
+#define _E_MEMO_TABLE_CONFIG_H_
+
+#include "e-memo-table.h"
+
+G_BEGIN_DECLS
+
+#define E_MEMO_TABLE_CONFIG(obj)          GTK_CHECK_CAST (obj, e_memo_table_config_get_type (), EMemoTableConfig)
+#define E_MEMO_TABLE_CONFIG_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, e_memo_table_config_get_type (), EMemoTableConfigClass)
+#define E_IS_MEMO_TABLE_CONFIG(obj)       GTK_CHECK_TYPE (obj, e_memo_table_config_get_type ())
+        
+typedef struct _EMemoTableConfig        EMemoTableConfig;
+typedef struct _EMemoTableConfigClass   EMemoTableConfigClass;
+typedef struct _EMemoTableConfigPrivate EMemoTableConfigPrivate;
+
+struct _EMemoTableConfig {
+	GObject parent;
+
+	EMemoTableConfigPrivate *priv;
+};
+
+struct _EMemoTableConfigClass {
+	GObjectClass parent_class;
+};
+
+GType          e_memo_table_config_get_type (void);
+EMemoTableConfig *e_memo_table_config_new (EMemoTable *table);
+EMemoTable *e_memo_table_config_get_table (EMemoTableConfig *view_config);
+void e_memo_table_config_set_table (EMemoTableConfig *view_config, EMemoTable *table);
+
+G_END_DECLS
+
+#endif
Index: calendar/gui/e-memo-table.c
===================================================================
RCS file: calendar/gui/e-memo-table.c
diff -N calendar/gui/e-memo-table.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memo-table.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1029 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Authors :
+ *  Damon Chaplin <damon ximian com>
+ *  Rodrigo Moya <rodrigo ximian com>
+ *  Nathan Owens <pianocomp81 yahoo com>
+ *
+ * Copyright 2000, 2001, 2002, 2003 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ * EMemoTable - displays the ECalComponent objects in a table (an ETable).
+ * Used for memos.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <gnome.h>
+#include <widgets/misc/e-gui-utils.h>
+#include <table/e-cell-checkbox.h>
+#include <table/e-cell-toggle.h>
+#include <table/e-cell-text.h>
+#include <table/e-cell-combo.h>
+#include <e-util/e-dialog-utils.h>
+#include <widgets/misc/e-cell-date-edit.h>
+#include <widgets/misc/e-cell-percent.h>
+
+#include "calendar-config.h"
+#include "dialogs/delete-comp.h"
+#include "dialogs/delete-error.h"
+#include "dialogs/memo-editor.h"
+#include "e-cal-model-memos.h"
+#include "e-memo-table.h"
+#include "e-cell-date-edit-text.h"
+#include "e-comp-editor-registry.h"
+#include "print.h"
+#include <e-util/e-icon-factory.h>
+#include "e-cal-popup.h"
+
+
+extern ECompEditorRegistry *comp_editor_registry;
+
+static void e_memo_table_class_init		(EMemoTableClass *klass);
+static void e_memo_table_init			(EMemoTable	*memo_table);
+static void e_memo_table_destroy		(GtkObject	*object);
+
+static void e_memo_table_on_double_click	(ETable		*table,
+						 gint		 row,
+						 gint		 col,
+						 GdkEvent	*event,
+						 EMemoTable *memo_table);
+static gint e_memo_table_show_popup_menu    	(ETable *table,
+						 GdkEvent *gdk_event,
+						 EMemoTable *memo_table);
+
+static gint e_memo_table_on_right_click		(ETable		*table,
+						 gint		 row,
+						 gint		 col,
+						 GdkEvent       *event,
+						 EMemoTable *memo_table);
+static gboolean e_memo_table_on_popup_menu  	(GtkWidget *widget,
+						 gpointer data);
+
+static gint e_memo_table_on_key_press		(ETable		*table,
+						 gint		 row,
+						 gint		 col,
+						 GdkEventKey	*event,
+						 EMemoTable *memo_table);
+
+static ECalModelComponent *get_selected_comp (EMemoTable *memo_table);
+static void open_memo (EMemoTable *memo_table, ECalModelComponent *comp_data);
+
+/* Signal IDs */
+enum {
+	USER_CREATED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* The icons to represent the task. */
+#define E_MEMO_MODEL_NUM_ICONS	2
+static const char* icon_names[E_MEMO_MODEL_NUM_ICONS] = {
+	"stock_notes", "stock_insert-note"
+};
+static GdkPixbuf* icon_pixbufs[E_MEMO_MODEL_NUM_ICONS] = { 0 };
+
+static GdkAtom clipboard_atom = GDK_NONE;
+
+G_DEFINE_TYPE (EMemoTable, e_memo_table, GTK_TYPE_TABLE);
+
+
+static void
+e_memo_table_class_init (EMemoTableClass *klass)
+{
+	GtkObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+
+	object_class = (GtkObjectClass *) klass;
+	widget_class = (GtkWidgetClass *) klass;
+
+	/* Method override */
+	object_class->destroy		= e_memo_table_destroy;
+
+	signals[USER_CREATED] =
+		g_signal_new ("user_created",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EMemoTableClass, user_created),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
+	/* clipboard atom */
+	if (!clipboard_atom)
+		clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+}
+
+/* Comparison function for the task-sort column.  Sorts by due date and then by
+ * priority.
+ *
+ * FIXME: Does this ever get called?? It doesn't seem to.
+ * I specified that the table should be sorted by this column, but it still
+ * never calls this function.
+ * Also, this assumes it is passed pointers to ECalComponents, but I think it
+ * may just be passed pointers to the 2 cell values.
+ */
+/*
+static gint
+task_compare_cb (gconstpointer a, gconstpointer b)
+{
+	ECalComponent *ca, *cb;
+	ECalComponentDateTime due_a, due_b;
+	int *prio_a, *prio_b;
+	int retval;
+
+	ca = E_CAL_COMPONENT (a);
+	cb = E_CAL_COMPONENT (b);
+
+	e_cal_component_get_due (ca, &due_a);
+	e_cal_component_get_due (cb, &due_b);
+	e_cal_component_get_priority (ca, &prio_a);
+	e_cal_component_get_priority (cb, &prio_b);
+
+	if (due_a.value && due_b.value) {
+		int v;
+
+		/* FIXME: TIMEZONES. But currently we have no way to get the
+		   ECal, so we can't get the timezone. *
+		v = icaltime_compare (*due_a.value, *due_b.value);
+
+		if (v == 0)
+			retval = compare_priorities (prio_a, prio_b);
+		else
+			retval = v;
+	} else if (due_a.value)
+		retval = -1;
+	else if (due_b.value)
+		retval = 1;
+	else
+		retval = compare_priorities (prio_a, prio_b);
+
+	e_cal_component_free_datetime (&due_a);
+	e_cal_component_free_datetime (&due_b);
+
+	if (prio_a)
+		e_cal_component_free_priority (prio_a);
+
+	if (prio_b)
+		e_cal_component_free_priority (prio_b);
+
+	return retval;
+}
+*/
+
+static void
+row_appended_cb (ECalModel *model, EMemoTable *memo_table) 
+{
+	g_signal_emit (memo_table, signals[USER_CREATED], 0);
+}
+
+static void
+e_memo_table_init (EMemoTable *memo_table)
+{
+	GtkWidget *table;
+	ETable *e_table;
+	ECell *cell;
+	ETableExtras *extras;
+	gint i;
+	AtkObject *a11y;
+
+	/* Create the model */
+
+	memo_table->model = (ECalModel *) e_cal_model_memos_new ();
+	g_signal_connect (memo_table->model, "row_appended", G_CALLBACK (row_appended_cb), memo_table);
+
+	/* Create the header columns */
+
+	extras = e_table_extras_new();
+
+	/*
+	 * Normal string fields.
+	 */
+	cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+	g_object_set (G_OBJECT (cell),
+		      "bg_color_column", E_CAL_MODEL_FIELD_COLOR,
+		      NULL);
+
+	e_table_extras_add_cell (extras, "calstring", cell);
+
+
+
+	/* Create pixmaps */
+
+	if (!icon_pixbufs[0])
+		for (i = 0; i < E_MEMO_MODEL_NUM_ICONS; i++) {
+			icon_pixbufs[i] = e_icon_factory_get_icon (icon_names[i], E_ICON_SIZE_LIST);
+		}
+
+	cell = e_cell_toggle_new (0, E_MEMO_MODEL_NUM_ICONS, icon_pixbufs);
+	e_table_extras_add_cell(extras, "icon", cell);
+	e_table_extras_add_pixbuf(extras, "icon", icon_pixbufs[0]);
+
+	/* Create the table */
+
+	table = e_table_scrolled_new_from_spec_file (E_TABLE_MODEL (memo_table->model),
+						     extras,
+						     EVOLUTION_ETSPECDIR "/e-memo-table.etspec",
+						     NULL);
+	/* FIXME: this causes a message from GLib about 'extras' having only a floating
+	   reference */
+	/* g_object_unref (extras); */
+
+	memo_table->etable = table;
+	gtk_table_attach (GTK_TABLE (memo_table), table, 0, 1, 0, 1,
+			  GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+	gtk_widget_show (table);
+
+
+	e_table = e_table_scrolled_get_table (E_TABLE_SCROLLED (table));
+	g_signal_connect (e_table, "double_click", G_CALLBACK (e_memo_table_on_double_click), memo_table);
+	g_signal_connect (e_table, "right_click", G_CALLBACK (e_memo_table_on_right_click), memo_table);
+	g_signal_connect (e_table, "key_press", G_CALLBACK (e_memo_table_on_key_press), memo_table);
+	g_signal_connect (e_table, "popup_menu", G_CALLBACK (e_memo_table_on_popup_menu), memo_table);
+	
+	a11y = gtk_widget_get_accessible (GTK_WIDGET(e_table));
+	if (a11y)
+		atk_object_set_name (a11y, _("Memo Table"));
+}
+
+
+/**
+ * e_memo_table_new:
+ * @Returns: a new #EMemoTable.
+ *
+ * Creates a new #EMemoTable.
+ **/
+GtkWidget *
+e_memo_table_new (void)
+{
+	GtkWidget *memo_table;
+
+	memo_table = GTK_WIDGET (g_object_new (e_memo_table_get_type (), NULL));
+
+	return memo_table;
+}
+
+
+/**
+ * e_memo_table_get_model:
+ * @memo_table: A calendar table.
+ * 
+ * Queries the calendar data model that a calendar table is using.
+ * 
+ * Return value: A memo model.
+ **/
+ECalModel *
+e_memo_table_get_model (EMemoTable *memo_table)
+{
+	g_return_val_if_fail (memo_table != NULL, NULL);
+	g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL);
+
+	return memo_table->model;
+}
+
+
+static void
+e_memo_table_destroy (GtkObject *object)
+{
+	EMemoTable *memo_table;
+
+	memo_table = E_MEMO_TABLE (object);
+
+	if (memo_table->model) {
+		g_object_unref (memo_table->model);
+		memo_table->model = NULL;
+	}
+
+	GTK_OBJECT_CLASS (e_memo_table_parent_class)->destroy (object);
+}
+
+/**
+ * e_memo_table_get_table:
+ * @memo_table: A calendar table.
+ * 
+ * Queries the #ETable widget that the calendar table is using.
+ * 
+ * Return value: The #ETable widget that the calendar table uses to display its
+ * data.
+ **/
+ETable *
+e_memo_table_get_table (EMemoTable *memo_table)
+{
+	g_return_val_if_fail (memo_table != NULL, NULL);
+	g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL);
+
+	return e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable));
+}
+
+void
+e_memo_table_open_selected (EMemoTable *memo_table)
+{
+	ECalModelComponent *comp_data;
+
+	comp_data = get_selected_comp (memo_table);
+	if (comp_data != NULL)
+		open_memo (memo_table, comp_data);
+}
+
+/* Used from e_table_selected_row_foreach(); puts the selected row number in an
+ * int pointed to by the closure data.
+ */
+static void
+get_selected_row_cb (int model_row, gpointer data)
+{
+	int *row;
+
+	row = data;
+	*row = model_row;
+}
+
+/* 
+ * Returns the component that is selected in the table; only works if there is
+ * one and only one selected row.
+ */
+static ECalModelComponent *
+get_selected_comp (EMemoTable *memo_table)
+{
+	ETable *etable;
+	int row;
+
+	etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable));
+	if (e_table_selected_count (etable) != 1)
+		return NULL;
+
+	row = -1;
+	e_table_selected_row_foreach (etable,
+				      get_selected_row_cb,
+				      &row);
+	g_assert (row != -1);
+
+	return e_cal_model_get_component_at (memo_table->model, row);
+}
+
+struct get_selected_uids_closure {
+	EMemoTable *memo_table;
+	GSList *objects;
+};
+
+/* Used from e_table_selected_row_foreach(), builds a list of the selected UIDs */
+static void
+add_uid_cb (int model_row, gpointer data)
+{
+	struct get_selected_uids_closure *closure;
+	ECalModelComponent *comp_data;
+
+	closure = data;
+
+	comp_data = e_cal_model_get_component_at (closure->memo_table->model, model_row);
+
+	closure->objects = g_slist_prepend (closure->objects, comp_data);
+}
+
+static GSList *
+get_selected_objects (EMemoTable *memo_table)
+{
+	struct get_selected_uids_closure closure;
+	ETable *etable;
+
+	closure.memo_table = memo_table;
+	closure.objects = NULL;
+
+	etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable));
+	e_table_selected_row_foreach (etable, add_uid_cb, &closure);
+
+	return closure.objects;
+}
+
+/* Deletes all of the selected components in the table */
+static void
+delete_selected_components (EMemoTable *memo_table)
+{
+	GSList *objs, *l;
+
+	objs = get_selected_objects (memo_table);
+
+	e_memo_table_set_status_message (memo_table, _("Deleting selected objects"));
+
+	for (l = objs; l; l = l->next) {
+		ECalModelComponent *comp_data = (ECalModelComponent *) l->data;
+		GError *error = NULL;
+		
+		e_cal_remove_object (comp_data->client, 
+				     icalcomponent_get_uid (comp_data->icalcomp), &error);
+		delete_error_dialog (error, E_CAL_COMPONENT_JOURNAL);
+		g_clear_error (&error);
+	}
+
+	e_memo_table_set_status_message (memo_table, NULL);
+
+	g_slist_free (objs);
+}
+
+/**
+ * e_memo_table_get_selected:
+ * @cal_table: 
+ * 
+ * Get the currently selected ECalModelComponent's on the table.
+ * 
+ * Return value: A GSList of the components, which should be
+ * g_slist_free'd when finished with.
+ **/
+GSList *
+e_memo_table_get_selected (EMemoTable *memo_table)
+{
+	return get_selected_objects(memo_table);
+}
+
+/**
+ * e_memo_table_delete_selected:
+ * @memo_table: A memo table.
+ * 
+ * Deletes the selected components in the table; asks the user first.
+ **/
+void
+e_memo_table_delete_selected (EMemoTable *memo_table)
+{
+	ETable *etable;
+	int n_selected;
+	ECalModelComponent *comp_data;
+	ECalComponent *comp = NULL;
+
+	g_return_if_fail (memo_table != NULL);
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable));
+
+	n_selected = e_table_selected_count (etable);
+	if (n_selected <= 0)
+		return;
+
+	if (n_selected == 1)
+		comp_data = get_selected_comp (memo_table);
+	else
+		comp_data = NULL;
+
+	/* FIXME: this may be something other than a TODO component */
+
+	if (comp_data) {
+		comp = e_cal_component_new ();
+		e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
+	}
+	
+	if (delete_component_dialog (comp, FALSE, n_selected, E_CAL_COMPONENT_JOURNAL,
+				     GTK_WIDGET (memo_table)))
+		delete_selected_components (memo_table);
+
+	/* free memory */
+	if (comp)
+		g_object_unref (comp);
+}
+
+/**
+ * e_memo_table_cut_clipboard:
+ * @memo_table: A calendar table.
+ *
+ * Cuts selected tasks in the given calendar table
+ */
+void
+e_memo_table_cut_clipboard (EMemoTable *memo_table)
+{
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	e_memo_table_copy_clipboard (memo_table);
+	delete_selected_components (memo_table);
+}
+
+/* callback for e_table_selected_row_foreach */
+static void
+copy_row_cb (int model_row, gpointer data)
+{
+	EMemoTable *memo_table;
+	ECalModelComponent *comp_data;
+	gchar *comp_str;
+	icalcomponent *child;
+
+	memo_table = E_MEMO_TABLE (data);
+
+	g_return_if_fail (memo_table->tmp_vcal != NULL);
+
+	comp_data = e_cal_model_get_component_at (memo_table->model, model_row);
+	if (!comp_data)
+		return;
+
+	/* add timezones to the VCALENDAR component */
+	e_cal_util_add_timezones_from_component (memo_table->tmp_vcal, comp_data->icalcomp);
+
+	/* add the new component to the VCALENDAR component */
+	comp_str = icalcomponent_as_ical_string (comp_data->icalcomp);
+	child = icalparser_parse_string (comp_str);
+	if (child) {
+		icalcomponent_add_component (memo_table->tmp_vcal,
+					     icalcomponent_new_clone (child));
+		icalcomponent_free (child);
+	}
+}
+
+/**
+ * e_memo_table_copy_clipboard:
+ * @memo_table: A calendar table.
+ *
+ * Copies selected tasks into the clipboard
+ */
+void
+e_memo_table_copy_clipboard (EMemoTable *memo_table)
+{
+	ETable *etable;
+	char *comp_str;
+	
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	/* create temporary VCALENDAR object */
+	memo_table->tmp_vcal = e_cal_util_new_top_level ();
+
+	etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable));
+	e_table_selected_row_foreach (etable, copy_row_cb, memo_table);
+	comp_str = icalcomponent_as_ical_string (memo_table->tmp_vcal);
+	gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (memo_table), clipboard_atom),
+				(const char *) comp_str,
+				g_utf8_strlen (comp_str, -1));
+	
+	/* free memory */
+	icalcomponent_free (memo_table->tmp_vcal);
+	memo_table->tmp_vcal = NULL;
+}
+
+static void
+clipboard_get_text_cb (GtkClipboard *clipboard, const gchar *text, EMemoTable *memo_table)
+{
+	icalcomponent *icalcomp;
+	char *uid;
+	ECalComponent *comp;
+	ECal *client;
+	icalcomponent_kind kind;
+
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	if (!text || !*text)
+		return;
+
+	icalcomp = icalparser_parse_string (text);
+	if (!icalcomp)
+		return;
+
+	/* check the type of the component */
+	kind = icalcomponent_isa (icalcomp);
+	if (kind != ICAL_VCALENDAR_COMPONENT &&
+	    kind != ICAL_VJOURNAL_COMPONENT) {
+		return;
+	}
+
+	client = e_cal_model_get_default_client (memo_table->model);
+	
+	e_memo_table_set_status_message (memo_table, _("Updating objects"));
+
+	if (kind == ICAL_VCALENDAR_COMPONENT) {
+		icalcomponent_kind child_kind;
+		icalcomponent *subcomp;
+		icalcomponent *vcal_comp;
+
+		vcal_comp = icalcomp;
+		subcomp = icalcomponent_get_first_component (
+			vcal_comp, ICAL_ANY_COMPONENT);
+		while (subcomp) {
+			child_kind = icalcomponent_isa (subcomp);
+			if (child_kind == ICAL_VJOURNAL_COMPONENT) {
+				ECalComponent *tmp_comp;
+
+				uid = e_cal_component_gen_uid ();
+				tmp_comp = e_cal_component_new ();
+				e_cal_component_set_icalcomponent (
+					tmp_comp, icalcomponent_new_clone (subcomp));
+				e_cal_component_set_uid (tmp_comp, uid);
+				free (uid);
+
+				/* FIXME should we convert start/due/complete times? */
+				/* FIXME Error handling */
+				e_cal_create_object (client, e_cal_component_get_icalcomponent (tmp_comp), NULL, NULL);
+
+				g_object_unref (tmp_comp);
+			}
+			subcomp = icalcomponent_get_next_component (
+				vcal_comp, ICAL_ANY_COMPONENT);
+		}
+	}
+	else {
+		comp = e_cal_component_new ();
+		e_cal_component_set_icalcomponent (comp, icalcomp);
+		uid = e_cal_component_gen_uid ();
+		e_cal_component_set_uid (comp, (const char *) uid);
+		free (uid);
+
+		e_cal_create_object (client, e_cal_component_get_icalcomponent (comp), NULL, NULL);
+
+		g_object_unref (comp);
+	}
+
+	e_memo_table_set_status_message (memo_table, NULL);
+}
+
+/**
+ * e_memo_table_paste_clipboard:
+ * @memo_table: A calendar table.
+ *
+ * Pastes tasks currently in the clipboard into the given calendar table
+ */
+void
+e_memo_table_paste_clipboard (EMemoTable *memo_table)
+{
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (memo_table), clipboard_atom),
+				    (GtkClipboardTextReceivedFunc) clipboard_get_text_cb, memo_table);
+}
+
+/* Opens a task in the task editor */
+static void
+open_memo (EMemoTable *memo_table, ECalModelComponent *comp_data)
+{
+	CompEditor *medit;
+	const char *uid;
+	
+	uid = icalcomponent_get_uid (comp_data->icalcomp);
+
+	medit = e_comp_editor_registry_find (comp_editor_registry, uid);
+	if (medit == NULL) {
+		ECalComponent *comp;
+
+		medit = COMP_EDITOR (memo_editor_new (comp_data->client));
+
+		comp = e_cal_component_new ();
+		e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
+		comp_editor_edit_comp (medit, comp);
+		
+		e_comp_editor_registry_add (comp_editor_registry, medit, FALSE);
+	}
+	
+	comp_editor_focus (medit);
+}
+
+/* Opens the task in the specified row */
+static void
+open_memo_by_row (EMemoTable *memo_table, int row)
+{
+	ECalModelComponent *comp_data;
+
+	comp_data = e_cal_model_get_component_at (memo_table->model, row);
+	open_memo (memo_table, comp_data);
+}
+
+static void
+e_memo_table_on_double_click (ETable *table,
+			      gint row, 
+			      gint col,
+			      GdkEvent *event,
+			      EMemoTable *memo_table)
+{
+	open_memo_by_row (memo_table, row);
+}
+
+
+static void
+e_memo_table_on_open_memo (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+	ECalModelComponent *comp_data;
+
+	comp_data = get_selected_comp (memo_table);
+	if (comp_data)
+		open_memo (memo_table, comp_data);
+}
+
+static void
+e_memo_table_on_save_as (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+	ECalModelComponent *comp_data;
+	char *filename;
+	char *ical_string;
+	FILE *file;
+
+	comp_data = get_selected_comp (memo_table);
+	if (comp_data == NULL)
+		return;
+	
+	filename = e_file_dialog_save (_("Save as..."));
+	if (filename == NULL)
+		return;
+	
+	ical_string = e_cal_get_component_as_string (comp_data->client, comp_data->icalcomp);
+	if (ical_string == NULL) {
+		g_warning ("Couldn't convert item to a string");
+		return;
+	}
+	
+	file = fopen (filename, "w");
+	if (file == NULL) {
+		g_warning ("Couldn't save item");
+		return;
+	}
+	
+	fprintf (file, ical_string);
+	g_free (ical_string);
+	fclose (file);
+}
+
+static void
+e_memo_table_on_print_memo (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+	ECalModelComponent *comp_data;
+	ECalComponent *comp;
+
+	comp_data = get_selected_comp (memo_table);
+	if (comp_data == NULL)
+		return;
+	
+	comp = e_cal_component_new ();
+	e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
+	print_comp (comp, comp_data->client, FALSE);
+
+	g_object_unref (comp);
+}
+
+static void
+e_memo_table_on_cut (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+
+	e_memo_table_cut_clipboard (memo_table);
+}
+
+static void
+e_memo_table_on_copy (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+
+	e_memo_table_copy_clipboard (memo_table);
+}
+
+static void
+e_memo_table_on_paste (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+	
+	e_memo_table_paste_clipboard (memo_table);
+}
+
+static void
+e_memo_table_on_forward (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+	ECalModelComponent *comp_data;
+
+	comp_data = get_selected_comp (memo_table);
+	if (comp_data) {
+		ECalComponent *comp;
+
+		comp = e_cal_component_new ();
+		e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
+		itip_send_comp (E_CAL_COMPONENT_METHOD_PUBLISH, comp, comp_data->client, NULL, NULL);
+
+		g_object_unref (comp);
+	}
+}
+
+/* Opens the URL of the memo */
+static void
+open_url_cb (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+	ECalModelComponent *comp_data;
+	icalproperty *prop;
+
+	comp_data = get_selected_comp (memo_table);
+	if (!comp_data)
+		return;
+
+	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
+	if (!prop)
+		return;
+
+	gnome_url_show (icalproperty_get_url (prop), NULL);
+}
+
+/* Callback for the "delete tasks" menu item */
+static void
+delete_cb (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	EMemoTable *memo_table = E_MEMO_TABLE (data);
+
+	e_memo_table_delete_selected (memo_table);
+}
+
+static EPopupItem memos_popup_items [] = {
+	{ E_POPUP_ITEM, "00.open", N_("_Open"), e_memo_table_on_open_memo, NULL, GTK_STOCK_OPEN, E_CAL_POPUP_SELECT_ONE },
+	{ E_POPUP_ITEM, "05.openweb", N_("Open _Web Page"), open_url_cb, NULL, NULL, E_CAL_POPUP_SELECT_ONE, E_CAL_POPUP_SELECT_HASURL },
+	{ E_POPUP_ITEM, "10.saveas", N_("_Save As..."), e_memo_table_on_save_as, NULL, GTK_STOCK_SAVE_AS, E_CAL_POPUP_SELECT_ONE },
+	{ E_POPUP_ITEM, "20.print", N_("_Print..."), e_memo_table_on_print_memo, NULL, GTK_STOCK_PRINT, E_CAL_POPUP_SELECT_ONE },
+
+	{ E_POPUP_BAR, "30.bar" },
+	
+	{ E_POPUP_ITEM, "40.cut", N_("C_ut"), e_memo_table_on_cut, NULL, GTK_STOCK_CUT, 0, E_CAL_POPUP_SELECT_EDITABLE },
+	{ E_POPUP_ITEM, "50.copy", N_("_Copy"), e_memo_table_on_copy, NULL, GTK_STOCK_COPY, 0, 0 },
+	{ E_POPUP_ITEM, "60.paste", N_("_Paste"), e_memo_table_on_paste, NULL, GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
+
+	{ E_POPUP_BAR, "70.bar" },
+
+	{ E_POPUP_ITEM, "80.forward", N_("_Forward as iCalendar"), e_memo_table_on_forward, NULL, "stock_mail-forward", E_CAL_POPUP_SELECT_ONE },
+
+	{ E_POPUP_BAR, "90.bar" },
+
+	{ E_POPUP_ITEM, "a0.delete", N_("_Delete"), delete_cb, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_ONE, E_CAL_POPUP_SELECT_EDITABLE },
+	{ E_POPUP_ITEM, "b0.deletemany", N_("_Delete Selected Memos"), delete_cb, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_MANY, E_CAL_POPUP_SELECT_EDITABLE },
+};
+
+static void
+emt_popup_free(EPopup *ep, GSList *items, void *data)
+{
+	g_slist_free(items);
+}
+
+static gint
+e_memo_table_show_popup_menu (ETable *table,
+				GdkEvent *gdk_event,
+				EMemoTable *memo_table)
+{
+	GtkMenu *menu;
+	GSList *selection, *l, *menus = NULL;
+	GPtrArray *events;
+	ECalPopup *ep;
+	ECalPopupTargetSelect *t;
+	int i;
+
+	selection = get_selected_objects (memo_table);
+	if (!selection)
+		return TRUE;
+
+	/** @HookPoint-ECalPopup: Tasks Table Context Menu
+	 * @Id: org.gnome.evolution.tasks.table.popup
+	 * @Class: org.gnome.evolution.calendar.popup:1.0
+	 * @Target: ECalPopupTargetSelect
+	 *
+	 * The context menu on the tasks table.
+	 */
+	ep = e_cal_popup_new("org.gnome.evolution.memos.table.popup");
+
+	events = g_ptr_array_new();
+	for (l=selection;l;l=g_slist_next(l))
+		g_ptr_array_add(events, e_cal_model_copy_component_data((ECalModelComponent *)l->data));
+	g_slist_free(selection);
+
+	t = e_cal_popup_target_new_select(ep, memo_table->model, events);
+	t->target.widget = (GtkWidget *)memo_table;
+
+	for (i=0;i<sizeof(memos_popup_items)/sizeof(memos_popup_items[0]);i++)
+		menus = g_slist_prepend(menus, &memos_popup_items[i]);
+	e_popup_add_items((EPopup *)ep, menus, NULL, emt_popup_free, memo_table);
+
+	menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
+
+	gtk_menu_popup(menu, NULL, NULL, NULL, NULL, gdk_event?gdk_event->button.button:0,
+		       gdk_event?gdk_event->button.time:gtk_get_current_event_time());
+
+	return TRUE;
+}
+
+static gint
+e_memo_table_on_right_click (ETable *table,
+				 gint row,
+				 gint col,
+				 GdkEvent *event,
+				 EMemoTable *memo_table)
+{
+	return e_memo_table_show_popup_menu (table, event, memo_table);
+}
+
+static gboolean
+e_memo_table_on_popup_menu (GtkWidget *widget, gpointer data)
+{
+	ETable *table = E_TABLE(widget);
+	g_return_val_if_fail(table, FALSE);
+
+	return e_memo_table_show_popup_menu (table, NULL,
+						 E_MEMO_TABLE(data));
+}
+
+static gint
+e_memo_table_on_key_press (ETable *table,
+			       gint row,
+			       gint col,
+			       GdkEventKey *event,
+			       EMemoTable *memo_table)
+{
+	if (event->keyval == GDK_Delete) {
+		delete_cb (NULL, NULL, memo_table);
+		return TRUE;
+	} else if ((event->keyval == GDK_o)
+		   &&(event->state & GDK_CONTROL_MASK)) {
+		open_memo_by_row (memo_table, row);
+		return TRUE;	
+	}
+
+	return FALSE;
+}
+
+/* Loads the state of the table (headers shown etc.) from the given file. */
+void
+e_memo_table_load_state	(EMemoTable *memo_table,
+			 gchar		*filename)
+{
+	struct stat st;
+
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	if (stat (filename, &st) == 0 && st.st_size > 0
+	    && S_ISREG (st.st_mode)) {
+		e_table_load_state (e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable)), filename);
+	}
+}
+
+
+/* Saves the state of the table (headers shown etc.) to the given file. */
+void
+e_memo_table_save_state (EMemoTable	*memo_table,
+			 gchar		*filename)
+{
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	e_table_save_state (e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable)),
+			    filename);
+}
+
+#ifdef TRANSLATORS_ONLY
+
+static char *test[] = {
+    N_("Click to add a memo")
+};
+
+#endif
+
+/* Displays messages on the status bar */
+#define EVOLUTION_MEMOS_PROGRESS_IMAGE "stock_notes"
+static GdkPixbuf *progress_icon = NULL;
+
+void
+e_memo_table_set_activity_handler (EMemoTable *memo_table, EActivityHandler *activity_handler)
+{
+	g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	memo_table->activity_handler = activity_handler;
+}
+
+void
+e_memo_table_set_status_message (EMemoTable *memo_table, const gchar *message)
+{
+        g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
+
+	if (!memo_table->activity_handler)
+		return;
+	
+        if (!message || !*message) {
+		if (memo_table->activity_id != 0) {
+			e_activity_handler_operation_finished (memo_table->activity_handler, memo_table->activity_id);
+			memo_table->activity_id = 0;
+		}
+        } else if (memo_table->activity_id == 0) {
+                char *client_id = g_strdup_printf ("%p", memo_table);
+		
+                if (progress_icon == NULL)
+                        progress_icon = e_icon_factory_get_icon (EVOLUTION_MEMOS_PROGRESS_IMAGE, E_ICON_SIZE_STATUS);
+
+                memo_table->activity_id = e_activity_handler_operation_started (memo_table->activity_handler, client_id,
+									        progress_icon, message, TRUE);
+
+                g_free (client_id);
+        } else {
+                e_activity_handler_operation_progressing (memo_table->activity_handler, memo_table->activity_id, message, -1.0);
+	}
+}
Index: calendar/gui/e-memo-table.etspec
===================================================================
RCS file: calendar/gui/e-memo-table.etspec
diff -N calendar/gui/e-memo-table.etspec
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memo-table.etspec	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,13 @@
+<ETableSpecification click-to-add="false" _click-to-add-message="Click to add a memo" draw-grid="true">
+  <ETableColumn model_col= "8" _title="Summary" expansion="3.0" minimum_width="10" resizable="true" cell="calstring" compare="string" priority="10"/>
+  <ETableColumn model_col="19" _title="Memo sort" cell="task-sort" compare="memo-sort" priority="-4"/>
+  <ETableColumn model_col="7" pixbuf="icon" _title="Type" expansion="1.0" minimum_width="16" resizable="false" cell="icon" compare="integer" priority="-4"/>
+  <ETableColumn model_col="0" _title="Categories" cell="calstring" compare="string" expansion="1.0" minimum_width="10" resizable="true" priority="-2"/>
+
+  <ETableState>
+    <column source="1"/>
+    <column source="0"/>
+    <column source="2"/>
+    <grouping></grouping>
+  </ETableState>
+</ETableSpecification>
Index: calendar/gui/e-memo-table.h
===================================================================
RCS file: calendar/gui/e-memo-table.h
diff -N calendar/gui/e-memo-table.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memo-table.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,106 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* 
+ * Author : 
+ *  Damon Chaplin <damon ximian com>
+ *  Nathan Owens <pianocomp81 yahoo com>
+ *
+ * Copyright 2000, Ximian, Inc.
+ * Copyright 2000, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of version 2 of the GNU General Public 
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#ifndef _E_MEMO_TABLE_H_
+#define _E_MEMO_TABLE_H_
+
+#include <gtk/gtktable.h>
+#include <table/e-table-scrolled.h>
+#include <widgets/misc/e-cell-date-edit.h>
+#include "e-activity-handler.h"
+#include "e-cal-model.h"
+
+G_BEGIN_DECLS
+
+/*
+ * EMemoTable - displays the iCalendar objects in a table (an ETable).
+ * Used for memo events and tasks.
+ */
+
+
+#define E_MEMO_TABLE(obj)          GTK_CHECK_CAST (obj, e_memo_table_get_type (), EMemoTable)
+#define E_MEMO_TABLE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, e_memo_table_get_type (), EMemoTableClass)
+#define E_IS_MEMO_TABLE(obj)       GTK_CHECK_TYPE (obj, e_memo_table_get_type ())
+
+
+typedef struct _EMemoTable       EMemoTable;
+typedef struct _EMemoTableClass  EMemoTableClass;
+
+
+struct _EMemoTable {
+	GtkTable table;
+
+	/* The model that we use */
+	ECalModel *model;
+
+	GtkWidget *etable;
+
+	/* Fields used for cut/copy/paste */
+	icalcomponent *tmp_vcal;
+
+	/* Activity ID for the EActivityHandler (i.e. the status bar).  */
+	EActivityHandler *activity_handler;
+	guint activity_id;
+};
+
+struct _EMemoTableClass {
+	GtkTableClass parent_class;
+
+	/* Notification signals */
+	void (* user_created) (EMemoTable *memo_table);
+};
+
+
+GtkType	   e_memo_table_get_type (void);
+GtkWidget* e_memo_table_new	(void);
+
+ECalModel *e_memo_table_get_model (EMemoTable *memo_table);
+
+ETable    *e_memo_table_get_table (EMemoTable *memo_table);
+
+void       e_memo_table_open_selected (EMemoTable *memo_table);
+void       e_memo_table_delete_selected (EMemoTable *memo_table);
+
+GSList    *e_memo_table_get_selected (EMemoTable *memo_table);
+
+/* Clipboard related functions */
+void       e_memo_table_cut_clipboard       (EMemoTable *memo_table);
+void       e_memo_table_copy_clipboard      (EMemoTable *memo_table);
+void       e_memo_table_paste_clipboard     (EMemoTable *memo_table);
+
+/* These load and save the state of the table (headers shown etc.) to/from
+   the given file. */
+void	   e_memo_table_load_state		(EMemoTable *memo_table,
+						 gchar		*filename);
+void	   e_memo_table_save_state		(EMemoTable *memo_table,
+						 gchar		*filename);
+
+void       e_memo_table_set_activity_handler (EMemoTable *memo_table,
+					      EActivityHandler *activity_handler);
+void       e_memo_table_set_status_message (EMemoTable *memo_table,
+					    const gchar *message);
+
+G_END_DECLS
+
+#endif /* _E_MEMO_TABLE_H_ */
Index: calendar/gui/e-memos.c
===================================================================
RCS file: calendar/gui/e-memos.c
diff -N calendar/gui/e-memos.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memos.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1180 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-memos.c
+ *
+ * Copyright (C) 2001-2003  Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Federico Mena Quintero <federico ximian com>
+ *	    Damon Chaplin <damon ximian com>
+ *          Rodrigo Moya <rodrigo ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnome.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <table/e-table-scrolled.h>
+#include <widgets/menus/gal-view-instance.h>
+#include <widgets/menus/gal-view-factory-etable.h>
+#include <widgets/menus/gal-view-etable.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-categories-config.h"
+#include "e-util/e-config-listener.h"
+#include "e-util/e-time-utils.h"
+#include "shell/e-user-creatable-items-handler.h"
+#include <libecal/e-cal-time-util.h>
+#include <libedataserver/e-url.h>
+#include <libedataserver/e-categories.h>
+#include "widgets/menus/gal-view-menus.h"
+#include "dialogs/delete-error.h"
+#include "e-calendar-marshal.h"
+#include "calendar-config.h"
+#include "cal-search-bar.h"
+#include "calendar-component.h"
+#include "comp-util.h"
+#include "e-memo-table-config.h"
+#include "misc.h"
+#include "memos-component.h"
+#include "e-cal-component-memo-preview.h"
+#include "e-memos.h"
+#include "common/authentication.h"
+
+
+/* Private part of the GnomeCalendar structure */
+struct _EMemosPrivate {
+	/* The memo lists for display */
+	GHashTable *clients;
+	GList *clients_list;
+	ECal *default_client;
+
+	ECalView *query;
+	
+	EConfigListener *config_listener;
+	
+	/* The EMemoTable showing the memos. */
+	GtkWidget   *memos_view;
+	EMemoTableConfig *memos_view_config;
+	
+	/* Calendar search bar for memos */
+	GtkWidget *search_bar;
+
+	/* Paned widget */
+	GtkWidget *paned;
+
+	/* The preview */
+	GtkWidget *preview;
+	
+	gchar *current_uid;
+	char *sexp;
+	guint update_timeout;
+	
+	/* View instance and the view menus handler */
+	GalViewInstance *view_instance;
+	GalViewMenus *view_menus;
+
+	GList *notifications;
+};
+
+static void setup_widgets (EMemos *memos);
+static void e_memos_destroy (GtkObject *object);
+static void update_view (EMemos *memos);
+
+static void config_categories_changed_cb (EConfigListener *config_listener, const char *key, gpointer user_data);
+static void backend_error_cb (ECal *client, const char *message, gpointer data);
+
+/* Signal IDs */
+enum {
+	SELECTION_CHANGED,
+	SOURCE_ADDED,
+	SOURCE_REMOVED,
+	LAST_SIGNAL
+};
+
+enum DndTargetType {
+	TARGET_VCALENDAR
+};
+
+static GtkTargetEntry list_drag_types[] = {
+	{ "text/calendar",                0, TARGET_VCALENDAR },
+	{ "text/x-calendar",              0, TARGET_VCALENDAR }
+};
+static const int num_list_drag_types = sizeof (list_drag_types) / sizeof (list_drag_types[0]);
+
+static guint e_memos_signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (EMemos, e_memos, GTK_TYPE_TABLE);
+
+/* Callback used when the cursor changes in the table */
+static void
+table_cursor_change_cb (ETable *etable, int row, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+	ECalModel *model;
+	ECalModelComponent *comp_data;
+	ECalComponent *comp;
+	const char *uid;
+
+	int n_selected;
+
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	n_selected = e_table_selected_count (etable);
+	
+	/* update the HTML widget */
+	if (n_selected != 1) {
+		e_cal_component_memo_preview_clear (E_CAL_COMPONENT_MEMO_PREVIEW (priv->preview));
+
+		return;
+	}
+	
+	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+	
+	comp_data = e_cal_model_get_component_at (model, e_table_get_cursor_row (etable));
+	comp = e_cal_component_new ();
+	e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp));
+
+	e_cal_component_memo_preview_display (E_CAL_COMPONENT_MEMO_PREVIEW (priv->preview), comp_data->client, comp);
+	
+	e_cal_component_get_uid (comp, &uid);
+	if (priv->current_uid)
+		g_free (priv->current_uid);
+	priv->current_uid = g_strdup (uid);
+	
+	g_object_unref (comp);
+}
+
+/* Callback used when the selection changes in the table. */
+static void
+table_selection_change_cb (ETable *etable, gpointer data)
+{
+	EMemos *memos;
+	int n_selected;
+
+	memos = E_MEMOS (data);
+
+	n_selected = e_table_selected_count (etable);
+	gtk_signal_emit (GTK_OBJECT (memos), e_memos_signals[SELECTION_CHANGED],
+			 n_selected);
+}
+
+static void
+user_created_cb (GtkWidget *view, EMemos *memos)
+{
+	EMemosPrivate *priv;	
+	ECal *ecal;
+	ECalModel *model;
+	
+	priv = memos->priv;
+
+	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+	ecal = e_cal_model_get_default_client (model);
+
+	e_memos_add_memo_source (memos, e_cal_get_source (ecal));
+}
+
+/* Callback used when the sexp in the search bar changes */
+static void
+search_bar_sexp_changed_cb (CalSearchBar *cal_search, const char *sexp, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	if (priv->sexp)
+		g_free (priv->sexp);
+	
+	priv->sexp = g_strdup (sexp);
+	
+	update_view (memos);
+}
+
+/* Callback used when the selected category in the search bar changes */
+static void
+search_bar_category_changed_cb (CalSearchBar *cal_search, const char *category, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+	ECalModel *model;
+
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+	e_cal_model_set_default_category (model, category);
+}
+
+static gboolean
+vpaned_resized_cb (GtkWidget *widget, GdkEventButton *event, EMemos *memos)
+{
+	calendar_config_set_task_vpane_pos (gtk_paned_get_position (GTK_PANED (widget)));
+
+	return FALSE;
+}
+
+static void
+set_timezone (EMemos *memos) 
+{
+	EMemosPrivate *priv;
+	icaltimezone *zone;
+	GList *l;
+	
+	priv = memos->priv;
+	
+	zone = calendar_config_get_icaltimezone ();
+	for (l = priv->clients_list; l != NULL; l = l->next) {
+		ECal *client = l->data;
+
+		if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
+			/* FIXME Error checking */
+			e_cal_set_default_timezone (client, zone, NULL);
+	}
+
+	if (priv->default_client && e_cal_get_load_state (priv->default_client) == E_CAL_LOAD_LOADED)
+		/* FIXME Error checking */
+		e_cal_set_default_timezone (priv->default_client, zone, NULL);
+
+	if (priv->preview)
+		e_cal_component_memo_preview_set_default_timezone (E_CAL_COMPONENT_MEMO_PREVIEW (priv->preview), zone);
+}
+
+static void
+timezone_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
+{
+	EMemos *memos = data;
+	
+	set_timezone (memos);
+}
+
+static void
+update_view (EMemos *memos)
+{
+	EMemosPrivate *priv;
+	ECalModel *model;
+	char *real_sexp = NULL;
+	char *new_sexp = NULL;
+	
+	priv = memos->priv;
+
+	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+		
+	if ((new_sexp = calendar_config_get_hide_completed_tasks_sexp()) != NULL) {
+		real_sexp = g_strdup_printf ("(and %s %s)", new_sexp, priv->sexp);
+		e_cal_model_set_search_query (model, real_sexp);
+		g_free (new_sexp);
+		g_free (real_sexp);
+	} else
+		e_cal_model_set_search_query (model, priv->sexp);
+	
+	e_cal_component_memo_preview_clear (E_CAL_COMPONENT_MEMO_PREVIEW (priv->preview));
+}
+
+static gboolean
+update_view_cb (EMemos *memos)
+{	
+	update_view (memos);
+
+	return TRUE;
+}
+
+static void
+model_row_changed_cb (ETableModel *etm, int row, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+	ECalModelComponent *comp_data;
+
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	if (priv->current_uid) {
+		const char *uid;
+
+		comp_data = e_cal_model_get_component_at (E_CAL_MODEL (etm), row);
+		if (comp_data) {
+			uid = icalcomponent_get_uid (comp_data->icalcomp);
+			if (!strcmp (uid ? uid : "", priv->current_uid)) {
+				ETable *etable;
+
+				etable = e_table_scrolled_get_table (
+					E_TABLE_SCROLLED (E_MEMO_TABLE (priv->memos_view)->etable));
+				table_cursor_change_cb (etable, 0, memos);
+			}
+		}
+	}
+}
+
+static void
+setup_config (EMemos *memos)
+{
+	EMemosPrivate *priv;
+	guint not;
+
+	priv = memos->priv;
+	
+	/* Timezone */
+	set_timezone (memos);
+	
+	not = calendar_config_add_notification_timezone (timezone_changed_cb, memos);
+	priv->notifications = g_list_prepend (priv->notifications, GUINT_TO_POINTER (not));
+}
+
+static void
+table_drag_data_get (ETable             *table,
+		     int                 row,
+		     int                 col,
+		     GdkDragContext     *context,
+		     GtkSelectionData   *selection_data,
+		     guint               info,
+		     guint               time,
+		     EMemos             *memos)
+{
+	EMemosPrivate *priv;
+	ECalModelComponent *comp_data;
+
+	priv = memos->priv;
+
+	if (priv->current_uid) {
+		ECalModel *model;
+
+		model = e_memo_table_get_model (
+			E_MEMO_TABLE (priv->memos_view));
+
+		comp_data = e_cal_model_get_component_at (model, row);
+
+		if (info == TARGET_VCALENDAR) {
+			/* we will pass an icalcalendar component for both types */
+			char *comp_str;
+			icalcomponent *vcal;
+		
+			vcal = e_cal_util_new_top_level ();
+			e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
+			icalcomponent_add_component (
+			        vcal,
+				icalcomponent_new_clone (comp_data->icalcomp));
+
+			comp_str = icalcomponent_as_ical_string (vcal);
+			if (comp_str) {
+				gtk_selection_data_set (selection_data, selection_data->target,
+							8, comp_str, strlen (comp_str));
+			}
+			icalcomponent_free (vcal);
+		}
+	}
+}
+
+static void 
+table_drag_data_delete (ETable         *table,
+			int             row,
+			int             col,
+			GdkDragContext *context,
+			EMemos         *memos)
+{
+	EMemosPrivate *priv;
+	ECalModelComponent *comp_data;
+	ECalModel *model;
+	gboolean read_only = TRUE;
+	
+	priv = memos->priv;
+	
+	model = e_memo_table_get_model (
+		E_MEMO_TABLE (priv->memos_view));
+	comp_data = e_cal_model_get_component_at (model, row);
+
+	e_cal_is_read_only (comp_data->client, &read_only, NULL);
+	if (read_only)
+		return;
+
+	e_cal_remove_object (comp_data->client, icalcomponent_get_uid (comp_data->icalcomp), NULL);
+}
+
+#define E_MEMOS_TABLE_DEFAULT_STATE					\
+	"<?xml version=\"1.0\"?>"					\
+	"<ETableState>"							\
+	"<column source=\"1\"/>"					\
+	"<column source=\"0\"/>"					\
+	"<column source=\"2\"/>"					\
+	"<grouping></grouping>"						\
+	"</ETableState>"
+
+static void
+pane_realized (GtkWidget *widget, EMemos *memos)
+{
+	gtk_paned_set_position ((GtkPaned *)widget, calendar_config_get_task_vpane_pos ());
+}
+
+static void
+setup_widgets (EMemos *memos)
+{
+	EMemosPrivate *priv;
+	ETable *etable;
+	ECalModel *model;
+
+	priv = memos->priv;
+
+	priv->search_bar = cal_search_bar_new (CAL_SEARCH_TASKS_DEFAULT);
+	g_signal_connect (priv->search_bar, "sexp_changed",
+			  G_CALLBACK (search_bar_sexp_changed_cb), memos);
+	g_signal_connect (priv->search_bar, "category_changed",
+			  G_CALLBACK (search_bar_category_changed_cb), memos);
+	
+	/* TODO Why doesn't this work?? */
+	config_categories_changed_cb (priv->config_listener, "/apps/evolution/general/category_master_list", memos);
+
+	gtk_table_attach (GTK_TABLE (memos), priv->search_bar, 0, 1, 0, 1,
+			  GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0, 0);
+	gtk_widget_show (priv->search_bar);
+
+	/* add the paned widget for the memo list and memo detail areas */
+	priv->paned = gtk_vpaned_new ();
+	g_signal_connect (priv->paned, "realize", G_CALLBACK (pane_realized), memos);
+
+	g_signal_connect (G_OBJECT (priv->paned), "button_release_event",
+			  G_CALLBACK (vpaned_resized_cb), memos);
+	gtk_table_attach (GTK_TABLE (memos), priv->paned, 0, 1, 1, 2,
+			  GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+	gtk_widget_show (priv->paned);
+
+	/* create the memo list */
+	priv->memos_view = e_memo_table_new ();
+	priv->memos_view_config = e_memo_table_config_new (E_MEMO_TABLE (priv->memos_view));
+	
+	g_signal_connect (priv->memos_view, "user_created", G_CALLBACK (user_created_cb), memos);
+
+	etable = e_table_scrolled_get_table (
+		E_TABLE_SCROLLED (E_MEMO_TABLE (priv->memos_view)->etable));
+	e_table_set_state (etable, E_MEMOS_TABLE_DEFAULT_STATE);
+	
+	gtk_paned_add1 (GTK_PANED (priv->paned), priv->memos_view);
+	gtk_widget_show (priv->memos_view);
+
+
+	e_table_drag_source_set (etable, GDK_BUTTON1_MASK,
+				 list_drag_types, num_list_drag_types,
+				 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_ASK);
+	
+	g_signal_connect (etable, "table_drag_data_get",
+			  G_CALLBACK(table_drag_data_get), memos);
+	g_signal_connect (etable, "table_drag_data_delete",
+			  G_CALLBACK(table_drag_data_delete), memos);
+
+	g_signal_connect (etable, "cursor_change", G_CALLBACK (table_cursor_change_cb), memos);
+	g_signal_connect (etable, "selection_change", G_CALLBACK (table_selection_change_cb), memos);
+
+	/* Timeout check to hide completed items */
+	priv->update_timeout = g_timeout_add_full (G_PRIORITY_LOW, 60000, (GSourceFunc) update_view_cb, memos, NULL);
+
+	/* create the memo detail */
+	priv->preview = e_cal_component_memo_preview_new ();
+	e_cal_component_memo_preview_set_default_timezone (E_CAL_COMPONENT_MEMO_PREVIEW (priv->preview), calendar_config_get_icaltimezone ());
+	gtk_paned_add2 (GTK_PANED (priv->paned), priv->preview);
+	gtk_widget_show (priv->preview);
+
+	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+	g_signal_connect (G_OBJECT (model), "model_row_changed",
+			  G_CALLBACK (model_row_changed_cb), memos);
+}
+
+/* Class initialization function for the gnome calendar */
+static void
+e_memos_class_init (EMemosClass *klass)
+{
+	GtkObjectClass *object_class;
+
+	object_class = (GtkObjectClass *) klass;
+
+	e_memos_signals[SELECTION_CHANGED] =
+		gtk_signal_new ("selection_changed",
+				GTK_RUN_LAST,
+				G_TYPE_FROM_CLASS (object_class), 
+				GTK_SIGNAL_OFFSET (EMemosClass, selection_changed),
+				gtk_marshal_NONE__INT,
+				GTK_TYPE_NONE, 1,
+				GTK_TYPE_INT);
+
+	e_memos_signals[SOURCE_ADDED] =
+		g_signal_new ("source_added",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (EMemosClass, source_added),
+			      NULL, NULL,
+			      e_calendar_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_OBJECT);
+
+	e_memos_signals[SOURCE_REMOVED] =
+		g_signal_new ("source_removed",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (EMemosClass, source_removed),
+			      NULL, NULL,
+			      e_calendar_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_OBJECT);
+
+	object_class->destroy = e_memos_destroy;
+
+	klass->selection_changed = NULL;
+	klass->source_added = NULL;
+	klass->source_removed = NULL;
+}
+
+
+static void
+config_categories_changed_cb (EConfigListener *config_listener, const char *key, gpointer user_data)
+{
+	GList *cat_list;
+	GPtrArray *cat_array;
+	EMemosPrivate *priv;
+	EMemos *memos = user_data;
+
+	priv = memos->priv;
+
+	cat_array = g_ptr_array_new ();
+	cat_list = e_categories_get_list ();
+	while (cat_list != NULL) {
+		if (e_categories_is_searchable ((const char *) cat_list->data))
+			g_ptr_array_add (cat_array, cat_list->data);
+		cat_list = g_list_remove (cat_list, cat_list->data);
+	}
+
+	cal_search_bar_set_categories (CAL_SEARCH_BAR(priv->search_bar), cat_array);
+
+	g_ptr_array_free (cat_array, TRUE);
+}
+
+/* Object initialization function for the gnome calendar */
+static void
+e_memos_init (EMemos *memos)
+{
+	EMemosPrivate *priv;
+	
+	priv = g_new0 (EMemosPrivate, 1);
+	memos->priv = priv;
+
+	setup_config (memos);
+	setup_widgets (memos);
+	
+	priv->config_listener = e_config_listener_new ();
+	g_signal_connect (priv->config_listener, "key_changed", G_CALLBACK (config_categories_changed_cb), memos);
+
+	priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);	
+	priv->query = NULL;
+	priv->view_instance = NULL;
+	priv->view_menus = NULL;
+	priv->current_uid = NULL;
+	priv->sexp = g_strdup ("#t");
+	priv->default_client = NULL;
+	update_view (memos);
+}
+
+/* Callback used when the set of categories changes in the calendar client */
+/* TODO this was actually taken out of tasks in 2.3.x
+ *      config_categories doesn't work, but this may - trying with memos*/
+/*
+static void
+client_categories_changed_cb (ECal *client, GPtrArray *categories, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	cal_search_bar_set_categories (CAL_SEARCH_BAR (priv->search_bar), categories);
+}
+*/
+
+GtkWidget *
+e_memos_new (void)
+{
+	EMemos *memos;
+
+	memos = g_object_new (e_memos_get_type (), NULL);
+
+	return GTK_WIDGET (memos);
+}
+
+
+void
+e_memos_set_ui_component (EMemos *memos,
+			  BonoboUIComponent *ui_component)
+{
+	g_return_if_fail (E_IS_MEMOS (memos));
+	g_return_if_fail (ui_component == NULL || BONOBO_IS_UI_COMPONENT (ui_component));
+
+	e_search_bar_set_ui_component (E_SEARCH_BAR (memos->priv->search_bar), ui_component);
+}
+
+
+static void
+e_memos_destroy (GtkObject *object)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (E_IS_MEMOS (object));
+
+	memos = E_MEMOS (object);
+	priv = memos->priv;
+
+	if (priv) {
+		GList *l;
+
+		/* unset the config listener */
+		if (priv->config_listener) {
+			g_signal_handlers_disconnect_matched (priv->config_listener,
+							      G_SIGNAL_MATCH_DATA,
+							      0, 0, NULL, NULL, memos);
+			g_object_unref (priv->config_listener);
+			priv->config_listener = NULL;
+		}
+		
+		/* disconnect from signals on all the clients */
+		for (l = priv->clients_list; l != NULL; l = l->next) {
+			g_signal_handlers_disconnect_matched (l->data, G_SIGNAL_MATCH_DATA,
+							      0, 0, NULL, NULL, memos);
+		}
+
+		g_hash_table_destroy (priv->clients);
+		g_list_free (priv->clients_list);
+
+		if (priv->default_client)
+			g_object_unref (priv->default_client);
+		priv->default_client = NULL;
+
+		if (priv->current_uid) {
+			g_free (priv->current_uid);
+			priv->current_uid = NULL;
+		}
+	
+		if (priv->sexp) {
+			g_free (priv->sexp);
+			priv->sexp = NULL;
+		}
+
+		if (priv->update_timeout) {
+			g_source_remove (priv->update_timeout);
+			priv->update_timeout = 0;
+		}
+	
+		if (priv->memos_view_config) {
+			g_object_unref (priv->memos_view_config);
+			priv->memos_view_config = NULL;
+		}
+		
+		for (l = priv->notifications; l; l = l->next)
+			calendar_config_remove_notification (GPOINTER_TO_UINT (l->data));
+		priv->notifications = NULL;
+
+		g_free (priv);
+		memos->priv = NULL;
+	}
+
+	if (GTK_OBJECT_CLASS (e_memos_parent_class)->destroy)
+		(* GTK_OBJECT_CLASS (e_memos_parent_class)->destroy) (object);
+}
+
+static void
+set_status_message (EMemos *memos, const char *message, ...)
+{
+	EMemosPrivate *priv;
+	va_list args;
+	char sz[2048], *msg_string = NULL;
+
+	if (message) {
+		va_start (args, message);
+		vsnprintf (sz, sizeof sz, message, args);
+		va_end (args);
+		msg_string = sz;
+	}
+
+	priv = memos->priv;
+	
+	e_memo_table_set_status_message (E_MEMO_TABLE (priv->memos_view), msg_string);
+}
+
+/* Callback from the calendar client when an error occurs in the backend */
+static void
+backend_error_cb (ECal *client, const char *message, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+	char *errmsg;
+	char *urinopwd;
+
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	urinopwd = get_uri_without_password (e_cal_get_uri (client));
+	errmsg = g_strdup_printf (_("Error on %s:\n %s"), urinopwd, message);
+	gnome_error_dialog_parented (errmsg, GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (memos))));
+	g_free (errmsg);
+	g_free (urinopwd);
+}
+
+/* Callback from the calendar client when the backend dies */
+static void
+backend_died_cb (ECal *client, gpointer data)
+{
+	EMemos *memos;
+	EMemosPrivate *priv;
+	ESource *source;
+	
+	memos = E_MEMOS (data);
+	priv = memos->priv;
+
+	source = g_object_ref (e_cal_get_source (client));
+
+	priv->clients_list = g_list_remove (priv->clients_list, client);
+	g_hash_table_remove (priv->clients,  e_source_peek_uid (source));
+
+	gtk_signal_emit (GTK_OBJECT (memos), e_memos_signals[SOURCE_REMOVED], source);
+
+	e_memo_table_set_status_message (E_MEMO_TABLE (e_memos_get_calendar_table (memos)), NULL);
+	
+	e_error_run (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (memos))),
+		     "calendar:memos-crashed", NULL);
+	
+	g_object_unref (source);
+}
+
+/* Callback from the calendar client when the calendar is opened */
+static void
+client_cal_opened_cb (ECal *ecal, ECalendarStatus status, EMemos *memos)
+{
+	ECalModel *model;
+	ESource *source;
+	EMemosPrivate *priv;
+
+	priv = memos->priv;
+
+	source = e_cal_get_source (ecal);
+
+	switch (status) {
+	case E_CALENDAR_STATUS_OK :
+		g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, client_cal_opened_cb, NULL);
+
+		set_status_message (memos, _("Loading memos"));
+		model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+		e_cal_model_add_client (model, ecal);
+
+		set_timezone (memos);
+		set_status_message (memos, NULL);
+		break;
+	case E_CALENDAR_STATUS_BUSY :
+		break;
+	case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
+		e_error_run (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (memos))), "calendar:prompt-no-contents-offline-memos", NULL);
+		break;
+	default :
+		/* Make sure the source doesn't disappear on us */
+		g_object_ref (source);
+
+		priv->clients_list = g_list_remove (priv->clients_list, ecal);
+		g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_DATA,
+						      0, 0, NULL, NULL, memos);
+
+		/* Do this last because it unrefs the client */
+		g_hash_table_remove (priv->clients,  e_source_peek_uid (source));
+
+		gtk_signal_emit (GTK_OBJECT (memos), e_memos_signals[SOURCE_REMOVED], source);
+
+		set_status_message (memos, NULL);
+		g_object_unref (source);
+
+		break;
+	}
+}
+
+static void
+default_client_cal_opened_cb (ECal *ecal, ECalendarStatus status, EMemos *memos)
+{
+	ECalModel *model;
+	ESource *source;
+	EMemosPrivate *priv;
+
+	priv = memos->priv;
+
+	source = e_cal_get_source (ecal);
+
+	switch (status) {
+	case E_CALENDAR_STATUS_OK :
+		g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, default_client_cal_opened_cb, NULL);
+		model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+		
+		set_timezone (memos);
+		e_cal_model_set_default_client (model, ecal);
+		set_status_message (memos, NULL);
+		break;
+	case E_CALENDAR_STATUS_BUSY:
+		break;
+	default :
+		/* Make sure the source doesn't disappear on us */
+		g_object_ref (source);
+
+		priv->clients_list = g_list_remove (priv->clients_list, ecal);
+		g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_DATA,
+						      0, 0, NULL, NULL, memos);
+
+		/* Do this last because it unrefs the client */
+		g_hash_table_remove (priv->clients,  e_source_peek_uid (source));
+
+		gtk_signal_emit (GTK_OBJECT (memos), e_memos_signals[SOURCE_REMOVED], source);
+
+		set_status_message (memos, NULL);
+		g_object_unref (priv->default_client);
+		priv->default_client = NULL;
+		g_object_unref (source);
+
+		break;
+	}
+}
+
+typedef void (*open_func) (ECal *, ECalendarStatus, EMemos *);
+
+static gboolean
+open_ecal (EMemos *memos, ECal *cal, gboolean only_if_exists, open_func of)
+{
+	EMemosPrivate *priv;
+
+	priv = memos->priv;
+	
+	set_status_message (memos, _("Opening memos at %s"), e_cal_get_uri (cal));
+
+	g_signal_connect (G_OBJECT (cal), "cal_opened", G_CALLBACK (of), memos);
+	e_cal_open_async (cal, only_if_exists);
+
+	return TRUE;
+}
+
+void
+e_memos_open_memo			(EMemos		*memos)
+{
+	EMemoTable *cal_table;
+                                                                                
+	cal_table = e_memos_get_calendar_table (memos);
+	e_memo_table_open_selected (cal_table);
+}
+
+void
+e_memos_new_memo (EMemos *memos)
+{
+	/* used for click_to_add ?? Can't figure out anything else it's used for */
+}
+
+gboolean
+e_memos_add_memo_source (EMemos *memos, ESource *source)
+{
+	EMemosPrivate *priv;
+	ECal *client;
+	const char *uid;
+
+	g_return_val_if_fail (memos != NULL, FALSE);
+	g_return_val_if_fail (E_IS_MEMOS (memos), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	priv = memos->priv;
+
+	uid = e_source_peek_uid (source);
+	client = g_hash_table_lookup (priv->clients, uid);
+	if (client) {
+		/* We already have it */
+
+		return TRUE;
+	} else {
+		ESource *default_source;
+		
+		if (priv->default_client) {
+			default_source = e_cal_get_source (priv->default_client);
+		
+			/* We don't have it but the default client is it */
+			if (!strcmp (e_source_peek_uid (default_source), uid))
+				client = g_object_ref (priv->default_client);
+		}
+
+		/* Create a new one */
+		if (!client) {
+			client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+			if (!client)
+				return FALSE;
+		}
+	}
+
+	g_signal_connect (G_OBJECT (client), "backend_error", G_CALLBACK (backend_error_cb), memos);
+/*	g_signal_connect (G_OBJECT (client), "categories_changed", G_CALLBACK (client_categories_changed_cb), memos); */
+	g_signal_connect (G_OBJECT (client), "backend_died", G_CALLBACK (backend_died_cb), memos);
+
+	/* add the client to internal structure */	
+	g_hash_table_insert (priv->clients, g_strdup (uid) , client);
+	priv->clients_list = g_list_prepend (priv->clients_list, client);
+
+	gtk_signal_emit (GTK_OBJECT (memos), e_memos_signals[SOURCE_ADDED], source);
+
+	open_ecal (memos, client, FALSE, client_cal_opened_cb);
+
+	return TRUE;
+}
+
+gboolean
+e_memos_remove_memo_source (EMemos *memos, ESource *source)
+{
+	EMemosPrivate *priv;
+	ECal *client;
+	ECalModel *model;
+	const char *uid;
+
+	g_return_val_if_fail (memos != NULL, FALSE);
+	g_return_val_if_fail (E_IS_MEMOS (memos), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	priv = memos->priv;
+
+	uid = e_source_peek_uid (source);
+	client = g_hash_table_lookup (priv->clients, uid);
+	if (!client) 
+		return TRUE;
+	
+
+	priv->clients_list = g_list_remove (priv->clients_list, client);
+	g_signal_handlers_disconnect_matched (client, G_SIGNAL_MATCH_DATA,
+					      0, 0, NULL, NULL, memos);	
+
+	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view));
+	e_cal_model_remove_client (model, client);
+
+	g_hash_table_remove (priv->clients, uid);
+       
+
+	gtk_signal_emit (GTK_OBJECT (memos), e_memos_signals[SOURCE_REMOVED], source);
+
+	return TRUE;
+}
+
+gboolean
+e_memos_set_default_source (EMemos *memos, ESource *source)
+{
+	EMemosPrivate *priv;
+	ECal *ecal;
+	
+	g_return_val_if_fail (memos != NULL, FALSE);
+	g_return_val_if_fail (E_IS_MEMOS (memos), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	priv = memos->priv;
+
+	ecal = g_hash_table_lookup (priv->clients, e_source_peek_uid (source));
+
+	if (priv->default_client)
+		g_object_unref (priv->default_client);
+
+	if (ecal) {
+		priv->default_client = g_object_ref (ecal);
+	} else {
+		priv->default_client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+		if (!priv->default_client)
+			return FALSE;
+	}
+
+	open_ecal (memos, priv->default_client, FALSE, default_client_cal_opened_cb);
+
+	return TRUE;
+}
+
+ECal *
+e_memos_get_default_client (EMemos *memos)
+{
+	EMemosPrivate *priv;
+	
+	g_return_val_if_fail (memos != NULL, NULL);
+	g_return_val_if_fail (E_IS_MEMOS (memos), NULL);
+
+	priv = memos->priv;
+
+	return e_cal_model_get_default_client (e_memo_table_get_model (E_MEMO_TABLE (priv->memos_view)));	
+}
+
+
+/**
+ * e_memos_delete_selected:
+ * @memos: A memos control widget.
+ * 
+ * Deletes the selected memos in the memo list.
+ **/
+void
+e_memos_delete_selected (EMemos *memos)
+{
+	EMemosPrivate *priv;
+	EMemoTable *cal_table;
+
+	g_return_if_fail (memos != NULL);
+	g_return_if_fail (E_IS_MEMOS (memos));
+
+	priv = memos->priv;
+
+	cal_table = E_MEMO_TABLE (priv->memos_view);
+	set_status_message (memos, _("Deleting selected objects..."));
+	e_memo_table_delete_selected (cal_table);
+	set_status_message (memos, NULL);
+
+	e_cal_component_memo_preview_clear (E_CAL_COMPONENT_MEMO_PREVIEW (priv->preview));
+}
+
+
+/* Callback used from the view collection when we need to display a new view */
+static void
+display_view_cb (GalViewInstance *instance, GalView *view, gpointer data)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (data);
+
+	if (GAL_IS_VIEW_ETABLE (view)) {
+		gal_view_etable_attach_table (GAL_VIEW_ETABLE (view), e_table_scrolled_get_table (E_TABLE_SCROLLED (E_MEMO_TABLE (memos->priv->memos_view)->etable)));
+	}
+
+	gtk_paned_set_position ((GtkPaned *)memos->priv->paned, calendar_config_get_task_vpane_pos ());
+}
+
+/**
+ * e_memos_setup_view_menus:
+ * @memos: A memos widget.
+ * @uic: UI controller to use for the menus.
+ * 
+ * Sets up the #GalView menus for a memos control.  This function should be
+ * called from the Bonobo control activation callback for this memos control.
+ * Also, the menus should be discarded using e_memos_discard_view_menus().
+ */
+void
+e_memos_setup_view_menus (EMemos *memos, BonoboUIComponent *uic)
+{
+	EMemosPrivate *priv;
+	GalViewFactory *factory;
+	ETableSpecification *spec;
+	char *dir;
+	static GalViewCollection *collection = NULL;
+
+	g_return_if_fail (memos != NULL);
+	g_return_if_fail (E_IS_MEMOS (memos));
+	g_return_if_fail (uic != NULL);
+	g_return_if_fail (BONOBO_IS_UI_COMPONENT (uic));
+
+	priv = memos->priv;
+
+	g_return_if_fail (priv->view_instance == NULL);
+
+	g_assert (priv->view_instance == NULL);
+	g_assert (priv->view_menus == NULL);
+
+	/* Create the view instance */
+
+	if (collection == NULL) {
+		collection = gal_view_collection_new ();
+
+		gal_view_collection_set_title (collection, _("Memos"));
+
+		dir = g_build_filename (memos_component_peek_base_directory (memos_component_peek ()), 
+					"memos", "views", NULL);
+	
+		gal_view_collection_set_storage_directories (collection,
+							     EVOLUTION_GALVIEWSDIR "/memos/",
+							     dir);
+		g_free (dir);
+
+		/* Create the views */
+
+		spec = e_table_specification_new ();
+		e_table_specification_load_from_file (spec, 
+						      EVOLUTION_ETSPECDIR "/e-memo-table.etspec");
+
+		factory = gal_view_factory_etable_new (spec);
+		g_object_unref (spec);
+		gal_view_collection_add_factory (collection, factory);
+		g_object_unref (factory);
+
+		/* Load the collection and create the menus */
+
+		gal_view_collection_load (collection);
+	}
+
+	priv->view_instance = gal_view_instance_new (collection, NULL);
+
+	priv->view_menus = gal_view_menus_new (priv->view_instance);
+	gal_view_menus_apply (priv->view_menus, uic, NULL);
+	g_signal_connect (priv->view_instance, "display_view", G_CALLBACK (display_view_cb), memos);
+	display_view_cb (priv->view_instance, gal_view_instance_get_current_view (priv->view_instance), memos);
+}
+
+/**
+ * e_memos_discard_view_menus:
+ * @memos: A memos widget.
+ * 
+ * Discards the #GalView menus used by a memos control.  This function should be
+ * called from the Bonobo control deactivation callback for this memos control.
+ * The menus should have been set up with e_memos_setup_view_menus().
+ **/
+void
+e_memos_discard_view_menus (EMemos *memos)
+{
+	EMemosPrivate *priv;
+
+	g_return_if_fail (memos != NULL);
+	g_return_if_fail (E_IS_MEMOS (memos));
+
+	priv = memos->priv;
+
+	g_return_if_fail (priv->view_instance != NULL);
+
+	g_assert (priv->view_instance != NULL);
+	g_assert (priv->view_menus != NULL);
+
+	g_object_unref (priv->view_instance);
+	priv->view_instance = NULL;
+
+	g_object_unref (priv->view_menus);
+	priv->view_menus = NULL;
+}
+
+/**
+ * e_memos_get_calendar_table:
+ * @memos: A memos widget.
+ * 
+ * Queries the #EMemoTable contained in a memos widget.
+ * 
+ * Return value: The #EMemoTable that the memos widget uses to display its
+ * information.
+ **/
+EMemoTable *
+e_memos_get_calendar_table (EMemos *memos)
+{
+	EMemosPrivate *priv;
+
+	g_return_val_if_fail (memos != NULL, NULL);
+	g_return_val_if_fail (E_IS_MEMOS (memos), NULL);
+
+	priv = memos->priv;
+	return E_MEMO_TABLE (priv->memos_view);
+}
Index: calendar/gui/e-memos.h
===================================================================
RCS file: calendar/gui/e-memos.h
diff -N calendar/gui/e-memos.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-memos.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,87 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-memos.h
+ *
+ * Copyright (C) 2001  Ximian, Inc.
+ * Copyright (C) 2001  Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Federico Mena Quintero <federico ximian com>
+ *	    Damon Chaplin <damon ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifndef _E_MEMOS_H_
+#define _E_MEMOS_H_
+
+#include <bonobo/bonobo-ui-component.h>
+#include <gtk/gtktable.h>
+#include <libedataserver/e-source.h>
+#include <libecal/e-cal.h>
+#include "e-memo-table.h"
+
+#define E_TYPE_MEMOS            (e_memos_get_type ())
+#define E_MEMOS(obj)            (GTK_CHECK_CAST ((obj), E_TYPE_MEMOS, EMemos))
+#define E_MEMOS_CLASS(klass)    (GTK_CHECK_CAST_CLASS ((klass), E_TYPE_MEMOS, \
+				 EMemosClass))
+#define E_IS_MEMOS(obj)         (GTK_CHECK_TYPE ((obj), E_TYPE_MEMOS))
+#define E_IS_MEMOS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), E_TYPE_MEMOS))
+
+typedef struct _EMemos EMemos;
+typedef struct _EMemosClass EMemosClass;
+typedef struct _EMemosPrivate EMemosPrivate;
+
+struct _EMemos {
+	GtkTable table;
+
+	/* Private data */
+	EMemosPrivate *priv;
+};
+
+struct _EMemosClass {
+	GtkTableClass parent_class;
+
+	/* Notification signals */
+	void (* selection_changed) (EMemos *memos, int n_selected);
+        void (* source_added)      (EMemos *memos, ESource *source);
+        void (* source_removed)    (EMemos *memos, ESource *source);
+};
+
+
+GtkType    e_memos_get_type        (void);
+GtkWidget *e_memos_construct       (EMemos *memos);
+
+GtkWidget *e_memos_new             (void);
+
+void       e_memos_set_ui_component  (EMemos            *memos,
+				      BonoboUIComponent *ui_component);
+
+gboolean   e_memos_add_memo_source (EMemos *memos, ESource *source);
+gboolean   e_memos_remove_memo_source (EMemos *memos, ESource *source);
+gboolean   e_memos_set_default_source (EMemos *memos, ESource *source);
+ECal      *e_memos_get_default_client    (EMemos *memos);
+
+void       e_memos_open_memo         (EMemos		*memos);
+void       e_memos_new_memo          (EMemos            *memos);
+void       e_memos_complete_selected (EMemos            *memos);
+void       e_memos_delete_selected   (EMemos            *memos);
+
+
+void e_memos_setup_view_menus (EMemos *memos, BonoboUIComponent *uic);
+void e_memos_discard_view_menus (EMemos *memos);
+
+EMemoTable *e_memos_get_calendar_table (EMemos *memos);
+
+#endif /* _E_MEMOS_H_ */
Index: calendar/gui/memos-component.c
===================================================================
RCS file: calendar/gui/memos-component.c
diff -N calendar/gui/memos-component.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/memos-component.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1330 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* memos-component.c
+ *
+ * Copyright (C) 2003  Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Rodrigo Moya <rodrigo ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-i18n.h>
+#include <bonobo/bonobo-exception.h>
+#include <gconf/gconf-client.h>
+#include <libecal/e-cal.h>
+#include <libedataserverui/e-source-selector.h>
+#include <shell/e-user-creatable-items-handler.h>
+#include "e-cal-model.h"
+#include "e-memos.h"
+#include "memos-component.h"
+#include "memos-control.h"
+#include "e-comp-editor-registry.h"
+#include "migration.h"
+#include "comp-util.h"
+#include "calendar-config.h"
+#include "e-cal-popup.h"
+#include "common/authentication.h"
+#include "dialogs/calendar-setup.h"
+#include "dialogs/comp-editor.h"
+#include "dialogs/copy-source-dialog.h"
+#include "dialogs/memo-editor.h"
+#include "widgets/misc/e-info-label.h"
+#include "e-util/e-icon-factory.h"
+#include "e-util/e-error.h"
+#include "calendar-component.h"
+
+#define CREATE_MEMO_ID               "memo"
+#define CREATE_MEMO_LIST_ID          "memo-list"
+
+enum DndTargetType {
+	DND_TARGET_TYPE_CALENDAR_LIST,
+};
+#define CALENDAR_TYPE "text/calendar"
+#define XCALENDAR_TYPE "text/x-calendar"
+#define WEB_BASE_URI "webcal://"
+#define PERSONAL_RELATIVE_URI "system"
+
+static GtkTargetEntry drag_types[] = {
+	{ CALENDAR_TYPE, 0, DND_TARGET_TYPE_CALENDAR_LIST },
+	{ XCALENDAR_TYPE, 0, DND_TARGET_TYPE_CALENDAR_LIST }
+};
+static gint num_drag_types = sizeof(drag_types) / sizeof(drag_types[0]);
+
+#define PARENT_TYPE bonobo_object_get_type ()
+
+static BonoboObjectClass *parent_class = NULL;
+
+/* Memos should have their own registry */
+extern ECompEditorRegistry *comp_editor_registry;
+
+
+typedef struct _MemosComponentView
+{
+	ESourceList *source_list;
+	
+	GSList *source_selection;
+	
+	EMemos *memos;
+	ETable *table;
+	ETableModel *model;
+
+	EInfoLabel *info_label;
+	GtkWidget *source_selector;
+	
+	BonoboControl *view_control;
+	BonoboControl *sidebar_control;
+	BonoboControl *statusbar_control;
+
+	GList *notifications;
+
+	EUserCreatableItemsHandler *creatable_items_handler;
+
+	EActivityHandler *activity_handler;
+} MemosComponentView;
+
+struct _MemosComponentPrivate {
+	char *base_directory;
+	char *config_directory;
+
+	ESourceList *source_list;
+	GSList *source_selection;
+
+	GList *views;
+	
+	ECal *create_ecal;
+	
+	GList *notifications;
+};
+
+/* #define d(x) x */
+#define d(x)
+
+static void
+ensure_sources (MemosComponent *component)
+{
+	GSList *groups;
+	ESourceList *source_list;
+	ESourceGroup *group;
+	ESourceGroup *on_this_computer;
+	ESourceGroup *on_the_web;
+	ESource *personal_source;
+	char *base_uri, *base_uri_proto;
+
+	on_this_computer = NULL;
+	on_the_web = NULL;
+	personal_source = NULL;
+
+	if (!e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL)) {
+		g_warning ("Could not get memo source list from GConf!");
+		return;
+	}
+
+	base_uri = g_build_filename (memos_component_peek_base_directory (component),
+				     "memos", "local",
+				     NULL);
+
+	base_uri_proto = g_strconcat ("file://", base_uri, NULL);
+
+	groups = e_source_list_peek_groups (source_list);
+	if (groups) {
+		/* groups are already there, we need to search for things... */
+		GSList *g;
+
+		for (g = groups; g; g = g->next) {
+
+			group = E_SOURCE_GROUP (g->data);
+
+			/* compare only file:// part. If user home dir name changes we do not want to create 
+			   one more group  */
+
+			if (!on_this_computer && !strncmp (base_uri_proto, e_source_group_peek_base_uri (group), 7))
+				on_this_computer = group;
+			else if (!on_the_web && !strcmp (WEB_BASE_URI, e_source_group_peek_base_uri (group)))
+				on_the_web = group;
+		}
+	}
+
+	if (on_this_computer) {
+		/* make sure "Personal" shows up as a source under
+		   this group */
+		GSList *sources = e_source_group_peek_sources (on_this_computer);
+		GSList *s;
+		for (s = sources; s; s = s->next) {
+			ESource *source = E_SOURCE (s->data);
+			if (!strcmp (PERSONAL_RELATIVE_URI, e_source_peek_relative_uri (source))) {
+				personal_source = source;
+				break;
+			}
+		}
+		/* Make sure we have the correct base uri. This can change when user's
+		   homedir name changes */
+		if (strcmp (base_uri_proto, e_source_group_peek_base_uri (on_this_computer))) {
+		    e_source_group_set_base_uri (on_this_computer, base_uri_proto);
+
+		    /* *sigh* . We shouldn't  need this sync call here as set_base_uri
+		       call results in synching to gconf, but that happens in idle loop
+		       and too late to prevent user seeing "Can not Open ... because of invalid uri" error.*/
+		    e_source_list_sync (source_list,NULL);
+		}
+	}
+	else {
+		/* create the local source group */
+		group = e_source_group_new (_("On This Computer"), base_uri_proto);
+		e_source_list_add_group (source_list, group, -1);
+
+		on_this_computer = group;
+	}
+
+	if (!personal_source) {
+		/* Create the default Person addressbook */
+		ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
+		e_source_group_add_source (on_this_computer, source, -1);
+
+		if (!calendar_config_get_primary_memos () && !calendar_config_get_memos_selected ()) {
+			GSList selected;
+
+			calendar_config_set_primary_memos (e_source_peek_uid (source));
+
+			selected.data = (gpointer)e_source_peek_uid (source);
+			selected.next = NULL;
+			calendar_config_set_memos_selected (&selected);
+		}
+
+		e_source_set_color (source, 0xBECEDD);
+		personal_source = source;
+	}
+
+	if (!on_the_web) {
+		/* Create the LDAP source group */
+		group = e_source_group_new (_("On The Web"), WEB_BASE_URI);
+		e_source_list_add_group (source_list, group, -1);
+
+		on_the_web = group;
+	}
+
+	component->priv->source_list = source_list;
+	g_free (base_uri_proto);
+	g_free (base_uri);
+}
+
+/* Utility functions.  */
+/* FIXME Some of these are duplicated from calendar-component.c */
+static gboolean
+is_in_selection (GSList *selection, ESource *source)
+{
+	GSList *l;
+	
+	for (l = selection; l; l = l->next) {
+		ESource *selected_source = l->data;
+		
+		if (!strcmp (e_source_peek_uid (selected_source), e_source_peek_uid (source)))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+is_in_uids (GSList *uids, ESource *source)
+{
+	GSList *l;
+	
+	for (l = uids; l; l = l->next) {
+		const char *uid = l->data;
+		
+		if (!strcmp (uid, e_source_peek_uid (source)))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+update_uris_for_selection (MemosComponentView *component_view)
+{
+	GSList *selection, *l, *uids_selected = NULL;
+	
+	selection = e_source_selector_get_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+	
+	for (l = component_view->source_selection; l; l = l->next) {
+		ESource *old_selected_source = l->data;
+
+		if (!is_in_selection (selection, old_selected_source))
+			e_memos_remove_memo_source (component_view->memos, old_selected_source);
+	}	
+	
+	for (l = selection; l; l = l->next) {
+		ESource *selected_source = l->data;
+		
+		e_memos_add_memo_source (component_view->memos, selected_source);
+		uids_selected = g_slist_append (uids_selected, (char *)e_source_peek_uid (selected_source));
+	}
+
+	e_source_selector_free_selection (component_view->source_selection);
+	component_view->source_selection = selection;
+
+	/* Save the selection for next time we start up */
+	calendar_config_set_memos_selected (uids_selected);
+	g_slist_free (uids_selected);
+}
+
+static void
+update_uri_for_primary_selection (MemosComponentView *component_view)
+{
+	ESource *source;
+	EMemoTable *cal_table;
+	ETable *etable;
+
+	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+	if (!source)
+		return;
+
+	/* Set the default */
+	e_memos_set_default_source (component_view->memos, source);
+
+	cal_table = e_memos_get_calendar_table (component_view->memos);
+	etable = e_memo_table_get_table (cal_table);
+
+	memos_control_sensitize_commands (component_view->view_control, component_view->memos, e_table_selected_count (etable));
+	
+	/* Save the selection for next time we start up */
+	calendar_config_set_primary_memos (e_source_peek_uid (source));
+}
+
+static void
+update_selection (MemosComponentView *component_view)
+{
+	GSList *selection, *uids_selected, *l;
+	
+	d(g_message("memos-component.c: update_selection called");)
+
+	/* Get the selection in gconf */
+	uids_selected = calendar_config_get_memos_selected ();
+
+	/* Remove any that aren't there any more */
+	selection = e_source_selector_get_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+
+	for (l = selection; l; l = l->next) {
+		ESource *source = l->data;
+
+		if (!is_in_uids (uids_selected, source)) 
+			e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector), source);
+	}
+	
+	e_source_selector_free_selection (selection);
+
+	/* Make sure the whole selection is there */
+	for (l = uids_selected; l; l = l->next) {
+		char *uid = l->data;
+		ESource *source;
+
+		source = e_source_list_peek_source_by_uid (component_view->source_list, uid);
+		if (source) 
+			e_source_selector_select_source (E_SOURCE_SELECTOR (component_view->source_selector), source);
+		
+		g_free (uid);
+	}
+	g_slist_free (uids_selected);
+}
+
+static void
+update_primary_selection (MemosComponentView *component_view)
+{
+	ESource *source = NULL;
+	char *uid;
+
+	uid = calendar_config_get_primary_memos ();
+	if (uid) {
+		source = e_source_list_peek_source_by_uid (component_view->source_list, uid);
+		g_free (uid);
+	}
+	
+	if (source) {
+		e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector), source);
+	} else {
+		/* Try to create a default if there isn't one */
+		source = e_source_list_peek_source_any (component_view->source_list);
+		if (source)
+			e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector), source);
+	}
+
+}
+
+
+/* Callbacks.  */
+/* TODO: doesn't work! */
+static void
+copy_memo_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	MemosComponentView *component_view = data;
+	ESource *selected_source;
+	
+	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+	if (!selected_source)
+		return;
+
+	copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source, E_CAL_SOURCE_TYPE_JOURNAL);
+}
+
+static void
+delete_memo_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	MemosComponentView *component_view = data;
+	ESource *selected_source;
+	ECal *cal;
+	char *uri;
+
+	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+	if (!selected_source)
+		return;
+
+	if (e_error_run((GtkWindow *)gtk_widget_get_toplevel(ep->target->widget),
+			"calendar:prompt-delete-memo-list", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
+		return;
+
+	/* first, ask the backend to remove the memo list */
+	uri = e_source_get_uri (selected_source);
+	cal = e_cal_model_get_client_for_uri (
+		e_memo_table_get_model (E_MEMO_TABLE (e_memos_get_calendar_table (component_view->memos))),
+		uri);
+	if (!cal)
+		cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
+	g_free (uri);
+	if (cal) {
+		if (e_cal_remove (cal, NULL)) {
+			if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
+								  selected_source)) {
+				e_memos_remove_memo_source (component_view->memos, selected_source);
+				e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
+								   selected_source);
+			}
+			
+			e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
+			e_source_list_sync (component_view->source_list, NULL);
+		}
+	}
+}
+
+static void
+new_memo_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	calendar_setup_new_memo_list (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)));
+}
+
+static void
+edit_memo_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
+{
+	MemosComponentView *component_view = data;
+	ESource *selected_source;
+
+	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
+	if (!selected_source)
+		return;
+
+	calendar_setup_edit_memo_list (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source);
+}
+
+static EPopupItem emc_source_popups[] = {
+	{ E_POPUP_ITEM, "10.new", N_("New Memo List"), new_memo_list_cb, NULL, "stock_notes", 0, 0 },
+	{ E_POPUP_ITEM, "15.copy", N_("Copy"), copy_memo_list_cb, NULL, "stock_folder-copy", 0, E_CAL_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "20.delete", N_("Delete"), delete_memo_list_cb, NULL, "stock_delete", 0, E_CAL_POPUP_SOURCE_USER|E_CAL_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_memo_list_cb, NULL, "stock_folder-properties", 0, E_CAL_POPUP_SOURCE_PRIMARY },
+};
+
+static void
+emc_source_popup_free(EPopup *ep, GSList *list, void *data)
+{
+	g_slist_free(list);
+}
+
+static gboolean
+popup_event_cb(ESourceSelector *selector, ESource *insource, GdkEventButton *event, MemosComponentView *component_view)
+{
+	ECalPopup *ep;
+	ECalPopupTargetSource *t;
+	GSList *menus = NULL;
+	int i;
+	GtkMenu *menu;
+
+	/** @HookPoint-ECalPopup: Memos Source Selector Context Menu
+	 * @Id: org.gnome.evolution.memos.source.popup
+	 * @Class: org.gnome.evolution.calendar.popup:1.0
+	 * @Target: ECalPopupTargetSource
+	 *
+	 * The context menu on the source selector in the memos window.
+	 */
+	ep = e_cal_popup_new("org.gnome.evolution.memos.source.popup");
+	t = e_cal_popup_target_new_source(ep, selector);
+	t->target.widget = (GtkWidget *)component_view->memos;
+
+	for (i=0;i<sizeof(emc_source_popups)/sizeof(emc_source_popups[0]);i++)
+		menus = g_slist_prepend(menus, &emc_source_popups[i]);
+
+	e_popup_add_items((EPopup *)ep, menus, NULL,emc_source_popup_free, component_view);
+
+	menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
+	gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
+
+	return TRUE;
+}
+
+static void
+source_selection_changed_cb (ESourceSelector *selector, MemosComponentView *component_view)
+{
+	update_uris_for_selection (component_view);
+}
+
+static void
+primary_source_selection_changed_cb (ESourceSelector *selector, MemosComponentView *component_view)
+{
+	update_uri_for_primary_selection (component_view);
+}
+
+static void
+source_added_cb (EMemos *memos, ESource *source, MemosComponentView *component_view)
+{
+	e_source_selector_select_source (E_SOURCE_SELECTOR (component_view->source_selector), source);
+}
+
+static void
+source_removed_cb (EMemos *memos, ESource *source, MemosComponentView *component_view)
+{
+	e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector), source);
+}
+
+static void
+set_info (MemosComponentView *component_view)
+{
+	GString *message = g_string_new ("");
+	int rows, selected_rows;
+	
+	rows = e_table_model_row_count (component_view->model);
+	selected_rows =  e_table_selected_count (component_view->table);
+
+	g_string_append_printf(message, ngettext("%d memo", "%d memos", rows), rows);
+	if (selected_rows > 0)
+		g_string_append_printf(message, ngettext(", %d selected", ", %d selected", selected_rows), selected_rows);
+
+	e_info_label_set_info (component_view->info_label, _("Memos"), message->str);
+
+	g_string_free (message, TRUE);
+}
+
+static void
+table_selection_change_cb (ETableModel *etm, MemosComponentView *component_view)
+{
+	set_info (component_view);
+}
+
+static void
+model_changed_cb (ETableModel *etm, MemosComponentView *component_view)
+{
+	set_info (component_view);
+}
+
+static void
+model_rows_inserted_cb (ETableModel *etm, int row, int count, MemosComponentView *component_view)
+{
+	set_info (component_view);
+}
+
+static void
+model_rows_deleted_cb (ETableModel *etm, int row, int count, MemosComponentView *component_view)
+{
+	set_info (component_view);
+}
+
+/* Evolution::Component CORBA methods */
+
+static void
+impl_upgradeFromVersion (PortableServer_Servant servant,
+			 CORBA_short major,
+			 CORBA_short minor,
+			 CORBA_short revision,
+			 CORBA_Environment *ev)
+{
+	GError *err = NULL;
+	MemosComponent *component = MEMOS_COMPONENT (bonobo_object_from_servant (servant));
+
+	if (!migrate_memos(component, major, minor, revision, &err)) {
+		GNOME_Evolution_Component_UpgradeFailed *failedex;
+
+		failedex = GNOME_Evolution_Component_UpgradeFailed__alloc();
+		failedex->what = CORBA_string_dup(_("Failed upgrading memos."));
+		failedex->why = CORBA_string_dup(err->message);
+		CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ex_GNOME_Evolution_Component_UpgradeFailed, failedex);
+	}
+
+	if (err)
+		g_error_free(err);
+}
+
+static gboolean
+selector_tree_drag_drop (GtkWidget *widget, 
+			 GdkDragContext *context, 
+			 int x, 
+			 int y, 
+			 guint time, 
+			 CalendarComponent *component)
+{
+	GtkTreeViewColumn *column;
+	int cell_x;
+	int cell_y;
+	GtkTreePath *path;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gpointer data;
+	
+	if (!gtk_tree_view_get_path_at_pos  (GTK_TREE_VIEW (widget), x, y, &path, 
+					     &column, &cell_x, &cell_y))
+		return FALSE;
+	
+	
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+	if (!gtk_tree_model_get_iter (model, &iter, path)) {
+		gtk_tree_path_free (path);
+		return FALSE;
+	}
+
+	gtk_tree_model_get (model, &iter, 0, &data, -1);
+	
+	if (E_IS_SOURCE_GROUP (data)) {
+		g_object_unref (data);
+		gtk_tree_path_free (path);
+		return FALSE;
+	}
+	
+	gtk_tree_path_free (path);
+	return TRUE;
+}
+	
+static gboolean
+selector_tree_drag_motion (GtkWidget *widget,
+			   GdkDragContext *context,
+			   int x,
+			   int y,
+			   guint time,
+			   gpointer user_data)
+{
+	GtkTreePath *path = NULL;
+	gpointer data = NULL;
+	GtkTreeViewDropPosition pos;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GdkDragAction action = GDK_ACTION_DEFAULT;
+	
+	if (!gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
+						x, y, &path, &pos))
+		goto finish;
+	
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	
+	if (!gtk_tree_model_get_iter (model, &iter, path))
+		goto finish;
+	
+	gtk_tree_model_get (model, &iter, 0, &data, -1);
+
+	if (E_IS_SOURCE_GROUP (data) || e_source_get_readonly (data))
+		goto finish;
+	
+	gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+	action = context->suggested_action;
+
+ finish:
+	if (path)
+		gtk_tree_path_free (path);
+	if (data)
+		g_object_unref (data);
+
+	gdk_drag_status (context, action, time);
+	return TRUE;
+}
+
+static gboolean
+update_single_object (ECal *client, icalcomponent *icalcomp)
+{
+	char *uid;
+	icalcomponent *tmp_icalcomp;
+
+	d(g_message("memos-component.c: update_single_object called");)
+
+	uid = (char *) icalcomponent_get_uid (icalcomp);
+	
+	if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, NULL))
+		return e_cal_modify_object (client, icalcomp, CALOBJ_MOD_ALL, NULL);
+
+	return e_cal_create_object (client, icalcomp, &uid, NULL);	
+}
+
+static gboolean
+update_objects (ECal *client, icalcomponent *icalcomp)
+{
+	icalcomponent *subcomp;
+	icalcomponent_kind kind;
+	
+	d(g_message("memos-component.c: update_objects called");)
+
+	kind = icalcomponent_isa (icalcomp);
+	if (kind == ICAL_VJOURNAL_COMPONENT)
+		return update_single_object (client, icalcomp);
+	else if (kind != ICAL_VCALENDAR_COMPONENT)
+		return FALSE;
+
+	subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
+	while (subcomp) {
+		gboolean success;
+		
+		kind = icalcomponent_isa (subcomp);
+		if (kind == ICAL_VTIMEZONE_COMPONENT) {
+			icaltimezone *zone;
+
+			zone = icaltimezone_new ();
+			icaltimezone_set_component (zone, subcomp);
+
+			success = e_cal_add_timezone (client, zone, NULL);
+			icaltimezone_free (zone, 1);
+			if (!success)
+				return success;
+		} else if (kind == ICAL_VJOURNAL_COMPONENT) {
+			success = update_single_object (client, subcomp);
+			if (!success)
+				return success;
+		}
+
+		subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT);
+	}
+
+	return TRUE;
+}
+
+static void
+selector_tree_drag_data_received (GtkWidget *widget, 
+				  GdkDragContext *context, 
+				  gint x, 
+				  gint y, 
+				  GtkSelectionData *data,
+				  guint info,
+				  guint time,
+				  gpointer user_data)
+{
+	GtkTreePath *path = NULL;
+	GtkTreeViewDropPosition pos;
+	gpointer source = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean success = FALSE;
+	icalcomponent *icalcomp = NULL;
+	ECal *client = NULL;
+
+	if (!gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
+						x, y, &path, &pos))
+		goto finish;
+	
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	
+	if (!gtk_tree_model_get_iter (model, &iter, path))
+		goto finish;
+       
+	
+	gtk_tree_model_get (model, &iter, 0, &source, -1);
+
+	if (E_IS_SOURCE_GROUP (source) || e_source_get_readonly (source))
+		goto finish;
+
+	icalcomp = icalparser_parse_string (data->data);
+	
+	if (icalcomp) {
+		char * uid;
+
+		/* FIXME deal with GDK_ACTION_ASK */
+		if (context->action == GDK_ACTION_COPY) {
+			uid = e_cal_component_gen_uid ();
+			icalcomponent_set_uid (icalcomp, uid);
+		}
+
+		client = auth_new_cal_from_source (source, 
+						   E_CAL_SOURCE_TYPE_JOURNAL);
+		
+		if (client) {
+			if (e_cal_open (client, TRUE, NULL)) {
+				success = TRUE;
+				update_objects (client, icalcomp);
+			}
+			
+			g_object_unref (client);
+		}
+		
+		icalcomponent_free (icalcomp);
+	}
+
+ finish:
+	if (source)
+		g_object_unref (source);
+	if (path)
+		gtk_tree_path_free (path);
+
+	gtk_drag_finish (context, success, context->action == GDK_ACTION_MOVE, time);
+}	
+
+static void
+selector_tree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, gpointer data)
+{
+	gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), 
+					NULL, GTK_TREE_VIEW_DROP_BEFORE);
+}
+
+
+static void
+control_activate_cb (BonoboControl *control, gboolean activate, gpointer data)
+{
+	MemosComponentView *component_view = data;
+
+	if (activate) {
+		BonoboUIComponent *uic;
+		uic = bonobo_control_get_ui_component (component_view->view_control);
+		
+		e_user_creatable_items_handler_activate (component_view->creatable_items_handler, uic);
+	}	
+}
+
+static void
+config_create_ecal_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
+{	
+	MemosComponent *component = data;
+	MemosComponentPrivate *priv;
+	
+	priv = component->priv;
+
+	g_object_unref (priv->create_ecal);
+	priv->create_ecal = NULL;
+	
+	priv->notifications = g_list_remove (priv->notifications, GUINT_TO_POINTER (id));
+}
+
+static ECal *
+setup_create_ecal (MemosComponent *component, MemosComponentView *component_view) 
+{
+	MemosComponentPrivate *priv;
+	ESource *source = NULL;
+	char *uid;
+	guint not;
+	
+	priv = component->priv;
+
+	if (component_view) {
+		ECal *default_ecal;
+
+		default_ecal = e_memos_get_default_client (component_view->memos);
+		if (default_ecal)
+			return default_ecal;
+	}
+	
+	if (priv->create_ecal)
+		return priv->create_ecal; 
+	
+	/* Get the current primary calendar, or try to set one if it doesn't already exist */
+	uid = calendar_config_get_primary_memos ();
+	if (uid) {
+		source = e_source_list_peek_source_by_uid (priv->source_list, uid);
+		g_free (uid);
+
+		priv->create_ecal = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+	}
+
+	if (!priv->create_ecal) {
+		/* Try to create a default if there isn't one */
+		source = e_source_list_peek_source_any (priv->source_list);
+		if (source)
+			priv->create_ecal = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+	}
+		
+	if (priv->create_ecal) {
+
+		if (!e_cal_open (priv->create_ecal, FALSE, NULL)) {
+			GtkWidget *dialog;
+			
+			dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+							 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+							 _("Unable to open the memo list '%s' for creating events and meetings"), 
+							   e_source_peek_name (source));
+			gtk_dialog_run (GTK_DIALOG (dialog));
+			gtk_widget_destroy (dialog);
+
+			return NULL;
+		}
+
+	} else {
+		GtkWidget *dialog;
+			
+		dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+						 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+						 _("There is no calendar available for creating memos"));
+		gtk_dialog_run (GTK_DIALOG (dialog));
+		gtk_widget_destroy (dialog);
+
+		return NULL;
+	}		
+
+	/* Handle the fact it may change on us */
+	not = calendar_config_add_notification_primary_memos (config_create_ecal_changed_cb, 
+							      component);
+	priv->notifications = g_list_prepend (priv->notifications, GUINT_TO_POINTER (not));
+
+	/* Save the primary source for use elsewhere */
+	calendar_config_set_primary_memos (e_source_peek_uid (source));
+
+	return priv->create_ecal ;
+}
+
+static gboolean
+create_new_memo (MemosComponent *memo_component, gboolean is_assigned, MemosComponentView *component_view)
+{
+	ECal *ecal;
+	MemosComponentPrivate *priv;
+	ECalComponent *comp;
+	MemoEditor *editor;
+	
+	priv = memo_component->priv;
+	
+	ecal = setup_create_ecal (memo_component, component_view);
+	if (!ecal)
+		return FALSE;
+
+	editor = memo_editor_new (ecal);
+	comp = cal_comp_memo_new_with_defaults (ecal);
+
+	comp_editor_edit_comp (COMP_EDITOR (editor), comp);
+	comp_editor_focus (COMP_EDITOR (editor));
+
+	e_comp_editor_registry_add (comp_editor_registry, COMP_EDITOR (editor), TRUE);
+
+	return TRUE;
+}
+
+static void
+create_local_item_cb (EUserCreatableItemsHandler *handler, const char *item_type_name, void *data)
+{
+	MemosComponent *memos_component = data;
+	MemosComponentPrivate *priv;
+	MemosComponentView *component_view = NULL;
+	GList *l;
+	
+	priv = memos_component->priv;
+	
+	for (l = priv->views; l; l = l->next) {
+		component_view = l->data;
+
+		if (component_view->creatable_items_handler == handler)
+			break;
+		
+		component_view = NULL;
+	}
+	
+	if (strcmp (item_type_name, CREATE_MEMO_ID) == 0) {
+		create_new_memo (memos_component, FALSE, component_view);
+	}
+	else if (strcmp (item_type_name, CREATE_MEMO_LIST_ID) == 0) {
+		calendar_setup_new_memo_list (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (component_view->memos))));
+	}
+}
+
+static MemosComponentView *
+create_component_view (MemosComponent *memos_component)
+{
+	MemosComponentPrivate *priv;
+	MemosComponentView *component_view;
+	GtkWidget *selector_scrolled_window, *vbox;
+	GtkWidget *statusbar_widget;
+	AtkObject *a11y;
+	
+	priv = memos_component->priv;
+
+	/* Create the calendar component view */
+	component_view = g_new0 (MemosComponentView, 1);
+	
+	/* Add the source lists */
+	component_view->source_list = g_object_ref (priv->source_list);
+	
+	/* Create sidebar selector */
+	component_view->source_selector = e_source_selector_new (memos_component->priv->source_list);
+	e_source_selector_set_select_new ((ESourceSelector *)component_view->source_selector, TRUE);
+	a11y = gtk_widget_get_accessible (GTK_WIDGET (component_view->source_selector));
+	atk_object_set_name (a11y, _("Memo Source Selector"));
+
+	g_signal_connect (component_view->source_selector, "drag-motion", G_CALLBACK (selector_tree_drag_motion), 
+			  memos_component);
+	g_signal_connect (component_view->source_selector, "drag-leave", G_CALLBACK (selector_tree_drag_leave), 
+			  memos_component);
+	g_signal_connect (component_view->source_selector, "drag-drop", G_CALLBACK (selector_tree_drag_drop), 
+			  memos_component);
+	g_signal_connect (component_view->source_selector, "drag-data-received", 
+			  G_CALLBACK (selector_tree_drag_data_received), memos_component);
+
+	gtk_drag_dest_set(component_view->source_selector, GTK_DEST_DEFAULT_ALL, drag_types,
+			  num_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+	gtk_widget_show (component_view->source_selector);
+
+	selector_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+	gtk_container_add (GTK_CONTAINER (selector_scrolled_window), component_view->source_selector);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (selector_scrolled_window),
+					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (selector_scrolled_window),
+					     GTK_SHADOW_IN);
+	gtk_widget_show (selector_scrolled_window);
+
+	component_view->info_label = (EInfoLabel *)e_info_label_new("stock_insert-note");
+	e_info_label_set_info(component_view->info_label, _("Memos"), "");
+	gtk_widget_show (GTK_WIDGET (component_view->info_label));
+
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_box_pack_start(GTK_BOX (vbox), GTK_WIDGET (component_view->info_label), FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX (vbox), selector_scrolled_window, TRUE, TRUE, 0);
+	gtk_widget_show (vbox);
+
+	component_view->sidebar_control = bonobo_control_new (vbox);
+
+	/* Create main view */
+	component_view->view_control = memos_control_new ();
+	if (!component_view->view_control) {
+		/* FIXME free memory */
+
+		return NULL;
+	}
+
+	component_view->memos = (EMemos *) bonobo_control_get_widget (component_view->view_control);
+	component_view->table = e_memo_table_get_table (e_memos_get_calendar_table (component_view->memos));
+	component_view->model = E_TABLE_MODEL (e_memo_table_get_model (e_memos_get_calendar_table (component_view->memos)));
+
+	/* This signal is thrown if backends die - we update the selector */
+	g_signal_connect (component_view->memos, "source_added", 
+			  G_CALLBACK (source_added_cb), component_view);
+	g_signal_connect (component_view->memos, "source_removed", 
+			  G_CALLBACK (source_removed_cb), component_view);
+
+	/* Create status bar */
+	statusbar_widget = e_task_bar_new ();
+	component_view->activity_handler = e_activity_handler_new ();
+	e_activity_handler_attach_task_bar (component_view->activity_handler, E_TASK_BAR (statusbar_widget));
+	gtk_widget_show (statusbar_widget);
+
+	component_view->statusbar_control = bonobo_control_new (statusbar_widget);
+	
+	e_memo_table_set_activity_handler (e_memos_get_calendar_table (component_view->memos), component_view->activity_handler);
+	
+	/* connect after setting the initial selections, or we'll get unwanted calls
+	   to calendar_control_sensitize_calendar_commands */
+	g_signal_connect (component_view->source_selector, "selection_changed",
+			  G_CALLBACK (source_selection_changed_cb), component_view);
+	g_signal_connect (component_view->source_selector, "primary_selection_changed",
+			  G_CALLBACK (primary_source_selection_changed_cb), component_view);
+	g_signal_connect (component_view->source_selector, "popup_event",
+			  G_CALLBACK (popup_event_cb), component_view);
+
+	/* Set up the "new" item handler */
+	component_view->creatable_items_handler = e_user_creatable_items_handler_new ("memos", create_local_item_cb, memos_component);
+	g_signal_connect (component_view->view_control, "activate", G_CALLBACK (control_activate_cb), component_view);
+
+	/* We use this to update the component information */
+	set_info (component_view);
+	g_signal_connect (component_view->table, "selection_change",
+			  G_CALLBACK (table_selection_change_cb), component_view);
+	g_signal_connect (component_view->model, "model_changed", 
+			  G_CALLBACK (model_changed_cb), component_view);
+	g_signal_connect (component_view->model, "model_rows_inserted",
+			  G_CALLBACK (model_rows_inserted_cb), component_view);
+	g_signal_connect (component_view->model, "model_rows_deleted",
+			  G_CALLBACK (model_rows_deleted_cb), component_view);
+
+	/* Load the selection from the last run */
+	update_selection (component_view);	
+	update_primary_selection (component_view);
+
+	return component_view;
+}
+
+static void
+destroy_component_view (MemosComponentView *component_view)
+{	
+	GList *l;
+	
+	if (component_view->source_list)
+		g_object_unref (component_view->source_list);
+
+	if (component_view->source_selection)
+		e_source_selector_free_selection (component_view->source_selection);
+	
+	for (l = component_view->notifications; l; l = l->next)
+		calendar_config_remove_notification (GPOINTER_TO_UINT (l->data));
+	g_list_free (component_view->notifications);
+
+	if (component_view->creatable_items_handler)
+		g_object_unref (component_view->creatable_items_handler);
+
+	if (component_view->activity_handler)
+		g_object_unref (component_view->activity_handler);
+
+	g_free (component_view);
+}
+
+static void
+view_destroyed_cb (gpointer data, GObject *where_the_object_was)
+{
+	MemosComponent *memos_component = data;
+	MemosComponentPrivate *priv;
+	GList *l;
+	
+	priv = memos_component->priv;
+
+	for (l = priv->views; l; l = l->next) {
+		MemosComponentView *component_view = l->data;
+		
+		if (G_OBJECT (component_view->view_control) == where_the_object_was) {
+			priv->views = g_list_remove (priv->views, component_view);
+			destroy_component_view (component_view);
+
+			break;
+		}
+	}
+}
+
+static void
+impl_createControls (PortableServer_Servant servant,
+		     Bonobo_Control *corba_sidebar_control,
+		     Bonobo_Control *corba_view_control,
+		     Bonobo_Control *corba_statusbar_control,
+		     CORBA_Environment *ev)
+{
+	MemosComponent *component = MEMOS_COMPONENT (bonobo_object_from_servant (servant));
+	MemosComponentPrivate *priv;
+	MemosComponentView *component_view;
+	
+	priv = component->priv;
+
+	/* Create the calendar component view */
+	component_view = create_component_view (component);
+	if (!component_view) {
+		/* FIXME Should we describe the problem in a control? */
+		bonobo_exception_set (ev, ex_GNOME_Evolution_Component_Failed);
+
+		return;
+	}
+
+	g_object_weak_ref (G_OBJECT (component_view->view_control), view_destroyed_cb, component);
+	priv->views = g_list_append (priv->views, component_view);
+	
+	/* Return the controls */
+	*corba_sidebar_control = CORBA_Object_duplicate (BONOBO_OBJREF (component_view->sidebar_control), ev);
+	*corba_view_control = CORBA_Object_duplicate (BONOBO_OBJREF (component_view->view_control), ev);
+	*corba_statusbar_control = CORBA_Object_duplicate (BONOBO_OBJREF (component_view->statusbar_control), ev);
+}
+
+static GNOME_Evolution_CreatableItemTypeList *
+impl__get_userCreatableItems (PortableServer_Servant servant,
+			      CORBA_Environment *ev)
+{
+	GNOME_Evolution_CreatableItemTypeList *list = GNOME_Evolution_CreatableItemTypeList__alloc ();
+
+	list->_length  = 2;
+	list->_maximum = list->_length;
+	list->_buffer  = GNOME_Evolution_CreatableItemTypeList_allocbuf (list->_length);
+
+	CORBA_sequence_set_release (list, FALSE);
+
+	list->_buffer[0].id = CREATE_MEMO_ID;
+	list->_buffer[0].description = _("New memo");
+	list->_buffer[0].menuDescription = _("_Memo");
+	list->_buffer[0].tooltip = _("Create a new memo");
+	list->_buffer[0].menuShortcut = 'o';
+	list->_buffer[0].iconName = "stock_insert-note";
+	list->_buffer[0].type = GNOME_Evolution_CREATABLE_OBJECT;
+
+	list->_buffer[1].id = CREATE_MEMO_LIST_ID;
+	list->_buffer[1].description = _("New memo list");
+	list->_buffer[1].menuDescription = _("Memo l_ist");
+	list->_buffer[1].tooltip = _("Create a new memo list");
+	list->_buffer[1].menuShortcut = 'i';
+	list->_buffer[1].iconName = "stock_notes";
+	list->_buffer[1].type = GNOME_Evolution_CREATABLE_FOLDER;
+
+	return list;
+}
+
+static void
+impl_requestCreateItem (PortableServer_Servant servant,
+			const CORBA_char *item_type_name,
+			CORBA_Environment *ev)
+{
+	MemosComponent *memos_component = MEMOS_COMPONENT (bonobo_object_from_servant (servant));
+	MemosComponentPrivate *priv;
+	
+	priv = memos_component->priv;	
+	
+	if (strcmp (item_type_name, CREATE_MEMO_ID) == 0) {
+		if (!create_new_memo (memos_component, FALSE, NULL))
+			bonobo_exception_set (ev, ex_GNOME_Evolution_Component_Failed);
+	}
+	else if (strcmp (item_type_name, CREATE_MEMO_LIST_ID) == 0) {
+		/* FIXME Should we use the last opened window? */
+		calendar_setup_new_memo_list (NULL);
+	}
+	else {
+		bonobo_exception_set (ev, ex_GNOME_Evolution_Component_UnknownType);
+	}
+}
+
+/* GObject methods.  */
+
+static void
+impl_dispose (GObject *object)
+{
+	MemosComponent *memos_component = MEMOS_COMPONENT (object);
+	MemosComponentPrivate *priv = memos_component->priv;
+	GList *l;
+	
+	if (priv->source_list != NULL) {
+		g_object_unref (priv->source_list);
+		priv->source_list = NULL;
+	}
+	if (priv->source_selection != NULL) {
+		e_source_selector_free_selection (priv->source_selection);
+		priv->source_selection = NULL;
+	}
+
+	if (priv->create_ecal) {
+		g_object_unref (priv->create_ecal);
+		priv->create_ecal = NULL;
+	}
+
+	for (l = priv->views; l; l = l->next) {
+		MemosComponentView *component_view = l->data;
+	
+		g_object_weak_unref (G_OBJECT (component_view->view_control), view_destroyed_cb, memos_component);
+	}
+	g_list_free (priv->views);
+	priv->views = NULL;
+
+	for (l = priv->notifications; l; l = l->next)
+		calendar_config_remove_notification (GPOINTER_TO_UINT (l->data));
+	g_list_free (priv->notifications);
+	priv->notifications = NULL;
+
+	(* G_OBJECT_CLASS (parent_class)->dispose) (object);
+}
+
+static void
+impl_finalize (GObject *object)
+{
+	MemosComponentPrivate *priv = MEMOS_COMPONENT (object)->priv;
+	GList *l;
+	
+	for (l = priv->views; l; l = l->next) {
+		MemosComponentView *component_view = l->data;
+		
+		destroy_component_view (component_view);
+	}
+	g_list_free (priv->views);
+
+	g_free (priv->base_directory);
+	g_free (priv->config_directory);
+	g_free (priv);
+
+	(* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+memos_component_class_init (MemosComponentClass *klass)
+{
+	POA_GNOME_Evolution_Component__epv *epv = &klass->epv;
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	epv->upgradeFromVersion      = impl_upgradeFromVersion;
+	epv->createControls          = impl_createControls;
+	epv->_get_userCreatableItems = impl__get_userCreatableItems;
+	epv->requestCreateItem       = impl_requestCreateItem;
+
+	object_class->dispose = impl_dispose;
+	object_class->finalize = impl_finalize;
+}
+
+static void
+memos_component_init (MemosComponent *component, MemosComponentClass *klass)
+{
+	MemosComponentPrivate *priv;
+
+	priv = g_new0 (MemosComponentPrivate, 1);
+	
+	printf("priv (MemosComponentnPrivate) == %p\n", priv);
+
+	priv->base_directory = g_build_filename (g_get_home_dir (), ".evolution", NULL);
+	priv->config_directory = g_build_filename (g_get_home_dir (),
+						   ".evolution", "memos", "config",
+						   NULL);
+
+	component->priv = priv;
+	ensure_sources (component);
+}
+
+/* Public API */
+
+MemosComponent *
+memos_component_peek (void)
+{
+	static MemosComponent *component = NULL;
+
+	if (component == NULL) {
+		component = g_object_new (memos_component_get_type (), NULL);
+
+		if (e_mkdir_hier (component->priv->config_directory, 0777) != 0) {
+			g_warning (G_STRLOC ": Cannot create directory %s: %s",
+				   component->priv->config_directory, g_strerror (errno));
+			g_object_unref (component);
+			component = NULL;
+		}
+	}
+
+	return component;
+}
+
+const char *
+memos_component_peek_base_directory (MemosComponent *component)
+{
+	return component->priv->base_directory;
+}
+
+const char *
+memos_component_peek_config_directory (MemosComponent *component)
+{
+	return component->priv->config_directory;
+}
+
+ESourceList *
+memos_component_peek_source_list (MemosComponent *component)
+{
+	return component->priv->source_list;	
+}
+
+BONOBO_TYPE_FUNC_FULL (MemosComponent, GNOME_Evolution_Component, PARENT_TYPE, memos_component)
Index: calendar/gui/memos-component.h
===================================================================
RCS file: calendar/gui/memos-component.h
diff -N calendar/gui/memos-component.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/memos-component.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,64 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* memos-component.h
+ *
+ * Copyright (C) 2003  Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Rodrigo Moya <rodrigo ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifndef _MEMOS_COMPONENT_H_
+#define _MEMOS_COMPONENT_H_
+
+#include <bonobo/bonobo-object.h>
+#include <libedataserver/e-source-list.h>
+#include <widgets/misc/e-activity-handler.h>
+#include "Evolution.h"
+
+
+#define MEMOS_TYPE_COMPONENT			(memos_component_get_type ())
+#define MEMOS_COMPONENT(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), MEMOS_TYPE_COMPONENT, MemosComponent))
+#define MEMOS_COMPONENT_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), MEMOS_TYPE_COMPONENT, MemosComponentClass))
+#define MEMOS_IS_COMPONENT(obj)			(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MEMOS_TYPE_COMPONENT))
+#define MEMOS_IS_COMPONENT_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE ((obj), MEMOS_TYPE_COMPONENT))
+
+
+typedef struct _MemosComponent        MemosComponent;
+typedef struct _MemosComponentPrivate MemosComponentPrivate;
+typedef struct _MemosComponentClass   MemosComponentClass;
+
+struct _MemosComponent {
+	BonoboObject parent;
+
+	MemosComponentPrivate *priv;
+};
+
+struct _MemosComponentClass {
+	BonoboObjectClass parent_class;
+
+	POA_GNOME_Evolution_Component__epv epv;
+};
+
+
+GType             memos_component_get_type  (void);
+MemosComponent   *memos_component_peek  (void);
+
+const char       *memos_component_peek_base_directory (MemosComponent *component);
+const char       *memos_component_peek_config_directory (MemosComponent *component);
+ESourceList      *memos_component_peek_source_list (MemosComponent *component);
+
+#endif /* _MEMOS_COMPONENT_H_ */
Index: calendar/gui/memos-control.c
===================================================================
RCS file: calendar/gui/memos-control.c
diff -N calendar/gui/memos-control.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/memos-control.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,361 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* memos-control.c
+ *
+ * Copyright (C) 2000, 2001, 2002, 2003  Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Damon Chaplin <damon ximian com>
+ *	    Ettore Perazzoli
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtksignal.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkmessagedialog.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-util.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-stock-icons.h>
+#include <libgnomeprint/gnome-print.h>
+#include <libgnomeprint/gnome-print-paper.h>
+#include <libgnomeprint/gnome-print-job.h>
+#include <libgnomeprintui/gnome-print-job-preview.h>
+#include <libgnomeprintui/gnome-print-paper-selector.h>
+#include <libgnomeprintui/gnome-print-preview.h>
+#include <libgnomeprintui/gnome-print-dialog.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-ui-util.h>
+#include <e-util/e-dialog-utils.h>
+#include <e-util/e-print.h>
+
+#include "calendar-config.h"
+#include "e-memos.h"
+#include "e-memo-table.h"
+#include "print.h"
+#include "memos-control.h"
+#include "evolution-shell-component-utils.h"
+
+#define FIXED_MARGIN                            .05
+
+
+static void memos_control_activate_cb		(BonoboControl		*control,
+						 gboolean		 activate,
+						 gpointer		 user_data);
+static void memos_control_open_memo_cmd		(BonoboUIComponent	*uic,
+						 gpointer		 data,
+						 const char		*path);
+static void memos_control_new_memo_cmd		(BonoboUIComponent	*uic,
+						 gpointer		 data,
+						 const char		*path);
+static void memos_control_cut_cmd               (BonoboUIComponent      *uic,
+						 gpointer                data,
+						 const gchar            *path);
+static void memos_control_copy_cmd              (BonoboUIComponent      *uic,
+						 gpointer                data,
+						 const gchar            *path);
+static void memos_control_paste_cmd             (BonoboUIComponent      *uic,
+						 gpointer                data,
+						 const gchar            *path);
+static void memos_control_delete_cmd		(BonoboUIComponent	*uic,
+						 gpointer		 data,
+						 const char		*path);
+static void memos_control_print_cmd		(BonoboUIComponent	*uic,
+						 gpointer		 data,
+						 const char		*path);
+static void memos_control_print_preview_cmd	(BonoboUIComponent	*uic,
+						 gpointer		 data,
+						 const char		*path);
+
+
+
+BonoboControl *
+memos_control_new (void)
+{
+	BonoboControl *control;
+	GtkWidget *memos;
+
+	memos = e_memos_new ();
+	if (!memos)
+		return NULL;
+	gtk_widget_show (memos);
+
+	control = bonobo_control_new (memos);
+	if (!control) {
+		gtk_widget_destroy (memos);
+		g_message ("control_factory_fn(): could not create the control!");
+		return NULL;
+	}
+
+	g_signal_connect (control, "activate", G_CALLBACK (memos_control_activate_cb), memos);
+
+	return control;
+}
+
+
+static void
+memos_control_activate_cb		(BonoboControl		*control,
+					 gboolean		 activate,
+					 gpointer		 user_data)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (user_data);
+
+	if (activate)
+		memos_control_activate (control, memos);
+	else
+		memos_control_deactivate (control, memos);
+}
+
+/* Sensitizes the UI Component menu/toolbar commands based on the number of
+ * selected memos.
+ */
+void
+memos_control_sensitize_commands (BonoboControl *control, EMemos *memos, int n_selected)
+{
+	BonoboUIComponent *uic;
+	gboolean read_only = TRUE;
+	ECal *ecal;
+	ECalModel *model;
+
+	uic = bonobo_control_get_ui_component (control);
+	g_assert (uic != NULL);
+
+	if (bonobo_ui_component_get_container (uic) == CORBA_OBJECT_NIL)
+		return;
+
+	model = e_memo_table_get_model (e_memos_get_calendar_table (memos));
+	ecal = e_cal_model_get_default_client (model);
+	if (ecal)
+		e_cal_is_read_only (ecal, &read_only, NULL);
+
+	bonobo_ui_component_set_prop (uic, "/commands/MemosOpenMemo", "sensitive",
+				      n_selected != 1 ? "0" : "1",
+				      NULL);
+	bonobo_ui_component_set_prop (uic, "/commands/MemosCut", "sensitive",
+				      n_selected == 0 || read_only ? "0" : "1",
+				      NULL);
+	bonobo_ui_component_set_prop (uic, "/commands/MemosCopy", "sensitive",
+				      n_selected == 0 ? "0" : "1",
+				      NULL);
+	bonobo_ui_component_set_prop (uic, "/commands/MemosPaste", "sensitive",
+				      read_only ? "0" : "1",
+				      NULL);
+	bonobo_ui_component_set_prop (uic, "/commands/MemosDelete", "sensitive",
+				      n_selected == 0 || read_only ? "0" : "1",
+				      NULL);
+}
+
+/* Callback used when the selection in the table changes */
+static void
+selection_changed_cb (EMemos *memos, int n_selected, gpointer data)
+{
+	BonoboControl *control;
+
+	control = BONOBO_CONTROL (data);
+
+	memos_control_sensitize_commands (control, memos, n_selected);
+}
+
+static BonoboUIVerb verbs [] = {
+	BONOBO_UI_VERB ("MemosOpenMemo", memos_control_open_memo_cmd),
+	BONOBO_UI_VERB ("MemosNewMemo", memos_control_new_memo_cmd),
+	BONOBO_UI_VERB ("MemosCut", memos_control_cut_cmd),
+	BONOBO_UI_VERB ("MemosCopy", memos_control_copy_cmd),
+	BONOBO_UI_VERB ("MemosPaste", memos_control_paste_cmd),
+	BONOBO_UI_VERB ("MemosDelete", memos_control_delete_cmd),
+	BONOBO_UI_VERB ("MemosPrint", memos_control_print_cmd),
+	BONOBO_UI_VERB ("MemosPrintPreview", memos_control_print_preview_cmd),
+
+	BONOBO_UI_VERB_END
+};
+
+void
+memos_control_activate (BonoboControl *control, EMemos *memos)
+{
+	Bonobo_UIContainer remote_uih;
+	BonoboUIComponent *uic;
+	int n_selected;
+	EMemoTable *cal_table;
+	ETable *etable;
+
+	uic = bonobo_control_get_ui_component (control);
+	g_assert (uic != NULL);
+
+	remote_uih = bonobo_control_get_remote_ui_container (control, NULL);
+	bonobo_ui_component_set_container (uic, remote_uih, NULL);
+	bonobo_object_release_unref (remote_uih, NULL);
+
+	e_memos_set_ui_component (memos, uic);
+
+	bonobo_ui_component_add_verb_list_with_data (uic, verbs, memos);
+
+	bonobo_ui_component_freeze (uic, NULL);
+
+	bonobo_ui_util_set_ui (uic, PREFIX,
+			       EVOLUTION_UIDIR "/evolution-memos.xml",
+			       "evolution-memos",
+			       NULL);
+
+	e_memos_setup_view_menus (memos, uic);
+
+	/* Signals from the memos widget; also sensitize the menu items as appropriate */
+
+	g_signal_connect (memos, "selection_changed", G_CALLBACK (selection_changed_cb), control);
+
+	cal_table = e_memos_get_calendar_table (memos);
+	etable = e_memo_table_get_table (cal_table);
+	n_selected = e_table_selected_count (etable);
+
+	memos_control_sensitize_commands (control, memos, n_selected);
+
+	bonobo_ui_component_thaw (uic, NULL);
+}
+
+
+void
+memos_control_deactivate (BonoboControl *control, EMemos *memos)
+{
+	BonoboUIComponent *uic = bonobo_control_get_ui_component (control);
+
+	g_assert (uic != NULL);
+
+	e_memos_set_ui_component (memos, NULL);
+
+	e_memos_discard_view_menus (memos);
+
+	/* Stop monitoring the "selection_changed" signal */
+	g_signal_handlers_disconnect_matched (memos, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, control);
+
+	bonobo_ui_component_rm (uic, "/", NULL);
+ 	bonobo_ui_component_unset_container (uic, NULL);
+}
+
+static void memos_control_open_memo_cmd		(BonoboUIComponent	*uic,
+						 gpointer		 data,
+						 const char		*path)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (data);
+	e_memos_open_memo (memos);
+}
+
+static void
+memos_control_new_memo_cmd		(BonoboUIComponent	*uic,
+					 gpointer		 data,
+					 const char		*path)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (data);
+	e_memos_new_memo (memos);
+}
+
+static void
+memos_control_cut_cmd                   (BonoboUIComponent      *uic,
+					 gpointer                data,
+					 const char             *path)
+{
+	EMemos *memos;
+	EMemoTable *cal_table;
+
+	memos = E_MEMOS (data);
+	cal_table = e_memos_get_calendar_table (memos);
+	e_memo_table_cut_clipboard (cal_table);
+}
+
+static void
+memos_control_copy_cmd                  (BonoboUIComponent      *uic,
+					 gpointer                data,
+					 const char             *path)
+{
+	EMemos *memos;
+	EMemoTable *cal_table;
+
+	memos = E_MEMOS (data);
+	cal_table = e_memos_get_calendar_table (memos);
+	e_memo_table_copy_clipboard (cal_table);
+}
+
+static void
+memos_control_paste_cmd                 (BonoboUIComponent      *uic,
+					 gpointer                data,
+					 const char             *path)
+{
+	EMemos *memos;
+	EMemoTable *cal_table;
+
+	memos = E_MEMOS (data);
+	cal_table = e_memos_get_calendar_table (memos);
+	e_memo_table_paste_clipboard (cal_table);
+}
+
+static void
+memos_control_delete_cmd		(BonoboUIComponent	*uic,
+					 gpointer		 data,
+					 const char		*path)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (data);
+	e_memos_delete_selected (memos);
+}
+
+
+static void
+print_memos (EMemos *memos, gboolean preview)
+{
+	EMemoTable *cal_table;
+	ETable *etable;
+
+	cal_table = e_memos_get_calendar_table (memos);
+	etable = e_memo_table_get_table (E_MEMO_TABLE (cal_table));
+
+	print_table (etable, _("Print Memos"), _("Memos"), preview);
+}
+
+/* File/Print callback */
+static void
+memos_control_print_cmd (BonoboUIComponent *uic,
+			 gpointer data,
+			 const char *path)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (data);
+
+	print_memos (memos, FALSE);
+}
+
+static void
+memos_control_print_preview_cmd (BonoboUIComponent *uic,
+				 gpointer data,
+				 const char *path)
+{
+	EMemos *memos;
+
+	memos = E_MEMOS (data);
+
+	print_memos (memos, TRUE);
+}
+
Index: calendar/gui/memos-control.h
===================================================================
RCS file: calendar/gui/memos-control.h
diff -N calendar/gui/memos-control.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/memos-control.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,35 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* memos-control.h
+ *
+ * Copyright (C) 2000, 2001, 2002, 2003  Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Federico Mena Quintero <federico ximian com>
+ *	    Damon Chaplin <damon ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ */
+
+#ifndef _MEMOS_CONTROL_H_
+#define _MEMOS_CONTROL_H_
+
+#include "e-memos.h"
+
+BonoboControl *memos_control_new                (void);
+void           memos_control_activate           (BonoboControl *control, EMemos *memos);
+void           memos_control_deactivate         (BonoboControl *control, EMemos *memos);
+void           memos_control_sensitize_commands (BonoboControl *control, EMemos *memos, int n_selected);
+
+#endif /* _MEMOS_CONTROL_H_ */
Index: calendar/gui/dialogs/memo-editor.c
===================================================================
RCS file: calendar/gui/dialogs/memo-editor.c
diff -N calendar/gui/dialogs/memo-editor.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/dialogs/memo-editor.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,286 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Evolution calendar - Memo editor dialog
+ *
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Authors: Miguel de Icaza <miguel ximian com>
+ *          Federico Mena-Quintero <federico ximian com>
+ *          Seth Alves <alves hungry com>
+ *          JP Rosevear <jpr ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glade/glade.h>
+#include <libgnome/gnome-i18n.h>
+
+#include "memo-page.h"
+#include "cancel-comp.h"
+#include "memo-editor.h"
+
+struct _MemoEditorPrivate {
+	MemoPage *memo_page;
+	
+	gboolean updating;	
+};
+
+static void memo_editor_set_e_cal (CompEditor *editor, ECal *client);
+static void memo_editor_edit_comp (CompEditor *editor, ECalComponent *comp);
+static gboolean memo_editor_send_comp (CompEditor *editor, ECalComponentItipMethod method);
+static void memo_editor_finalize (GObject *object);
+
+static void refresh_memo_cmd (GtkWidget *widget, gpointer data);
+static void cancel_memo_cmd (GtkWidget *widget, gpointer data);
+static void forward_cmd (GtkWidget *widget, gpointer data);
+
+static void model_row_change_insert_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
+static void model_row_delete_cb (GtkTreeModel *model, GtkTreePath *path, gpointer data);
+
+G_DEFINE_TYPE (MemoEditor, memo_editor, TYPE_COMP_EDITOR);
+
+
+
+/**
+ * memo_editor_get_type:
+ *
+ * Registers the #MemoEditor class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the #MemoEditor class.
+ **/
+
+/* Class initialization function for the event editor */
+static void
+memo_editor_class_init (MemoEditorClass *klass)
+{
+	GObjectClass *object_class;
+	CompEditorClass *editor_class;
+
+	object_class = (GObjectClass *) klass;
+	editor_class = (CompEditorClass *) klass;
+
+	editor_class->set_e_cal = memo_editor_set_e_cal;
+	editor_class->edit_comp = memo_editor_edit_comp;
+	editor_class->send_comp = memo_editor_send_comp;
+
+	object_class->finalize = memo_editor_finalize;
+}
+
+static void
+init_widgets (MemoEditor *me)
+{
+	MemoEditorPrivate *priv;
+
+	priv = me->priv;
+}
+
+static void
+client_changed_cb (CompEditorPage *page, ECal *client, gpointer user_data)
+{
+/*	set_menu_sens (MEMO_EDITOR (user_data)); */
+}
+
+/* Object initialization function for the memo editor */
+static void
+memo_editor_init (MemoEditor *te)
+{
+	MemoEditorPrivate *priv;
+	
+	priv = g_new0 (MemoEditorPrivate, 1);
+	te->priv = priv;
+
+	priv->updating = FALSE;	
+
+	/* TODO add help stuff */
+/*	comp_editor_set_help_section (COMP_EDITOR (te), "usage-calendar-memo"); */
+}
+
+MemoEditor *
+memo_editor_construct (MemoEditor *me, ECal *client)
+{
+	MemoEditorPrivate *priv;
+	
+	gboolean read_only = FALSE;
+	
+	priv = me->priv;
+
+	priv->memo_page = memo_page_new ();
+	g_object_ref (priv->memo_page);
+	gtk_object_sink (GTK_OBJECT (priv->memo_page));
+	comp_editor_append_page (COMP_EDITOR (me), 
+				 COMP_EDITOR_PAGE (priv->memo_page),
+				 _("Memo"));
+	g_signal_connect (G_OBJECT (priv->memo_page), "client_changed",
+			  G_CALLBACK (client_changed_cb), me);
+
+	if (!e_cal_is_read_only (client, &read_only, NULL))
+		read_only = TRUE;
+	comp_editor_sensitize_attachment_bar (COMP_EDITOR (me), !read_only);
+
+	comp_editor_set_e_cal (COMP_EDITOR (me), client);
+
+	init_widgets (me);
+
+	return me;
+}
+
+static void
+memo_editor_set_e_cal (CompEditor *editor, ECal *client)
+{
+	MemoEditor *te;
+	MemoEditorPrivate *priv;
+
+	te = MEMO_EDITOR (editor);
+	priv = te->priv;
+
+	if (COMP_EDITOR_CLASS (memo_editor_parent_class)->set_e_cal)
+		COMP_EDITOR_CLASS (memo_editor_parent_class)->set_e_cal (editor, client);
+}
+
+static void
+memo_editor_edit_comp (CompEditor *editor, ECalComponent *comp)
+{
+	MemoEditor *me;
+	MemoEditorPrivate *priv;
+	ECalComponentOrganizer organizer;
+	ECal *client;
+	
+	me = MEMO_EDITOR (editor);
+	priv = me->priv;
+
+	priv->updating = TRUE;
+
+	if (COMP_EDITOR_CLASS (memo_editor_parent_class)->edit_comp)
+		COMP_EDITOR_CLASS (memo_editor_parent_class)->edit_comp (editor, comp);
+
+	client = comp_editor_get_e_cal (COMP_EDITOR (editor));
+
+	priv->updating = FALSE;
+}
+
+static gboolean
+memo_editor_send_comp (CompEditor *editor, ECalComponentItipMethod method)
+{
+	MemoEditor *me = MEMO_EDITOR (editor);
+	MemoEditorPrivate *priv;
+	ECalComponent *comp = NULL;
+
+	priv = me->priv;
+
+	if (COMP_EDITOR_CLASS (memo_editor_parent_class)->send_comp)
+		return COMP_EDITOR_CLASS (memo_editor_parent_class)->send_comp (editor, method);
+
+	return FALSE;
+}
+
+/* Destroy handler for the event editor */
+static void
+memo_editor_finalize (GObject *object)
+{
+	MemoEditor *me;
+	MemoEditorPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (IS_MEMO_EDITOR (object));
+
+	me = MEMO_EDITOR (object);
+	priv = me->priv;
+
+	if (priv->memo_page) {
+		g_object_unref (priv->memo_page);
+		priv->memo_page = NULL;
+	}
+	
+	g_free (priv);
+
+	if (G_OBJECT_CLASS (memo_editor_parent_class)->finalize)
+		(* G_OBJECT_CLASS (memo_editor_parent_class)->finalize) (object);
+}
+
+/**
+ * memo_editor_new:
+ * @client: an ECal
+ *
+ * Creates a new event editor dialog.
+ *
+ * Return value: A newly-created event editor dialog, or NULL if the event
+ * editor could not be created.
+ **/
+MemoEditor *
+memo_editor_new (ECal *client)
+{
+	MemoEditor *me;
+
+	me = g_object_new (TYPE_MEMO_EDITOR, NULL);
+	return memo_editor_construct (me, client);
+}
+
+static void
+refresh_memo_cmd (GtkWidget *widget, gpointer data)
+{
+	MemoEditor *me = MEMO_EDITOR (data);
+
+	comp_editor_send_comp (COMP_EDITOR (me), E_CAL_COMPONENT_METHOD_REFRESH);
+}
+
+static void
+cancel_memo_cmd (GtkWidget *widget, gpointer data)
+{
+	MemoEditor *me = MEMO_EDITOR (data);
+	ECalComponent *comp;
+	
+	comp = comp_editor_get_current_comp (COMP_EDITOR (me));
+	if (cancel_component_dialog ((GtkWindow *) me,
+				     comp_editor_get_e_cal (COMP_EDITOR (me)), comp, FALSE)) {
+		comp_editor_send_comp (COMP_EDITOR (me), E_CAL_COMPONENT_METHOD_CANCEL);
+		comp_editor_delete_comp (COMP_EDITOR (me));
+	}
+}
+
+static void
+forward_cmd (GtkWidget *widget, gpointer data)
+{
+	MemoEditor *me = MEMO_EDITOR (data);
+	
+	if (comp_editor_save_comp (COMP_EDITOR (me), TRUE))
+		comp_editor_send_comp (COMP_EDITOR (me), E_CAL_COMPONENT_METHOD_PUBLISH);
+}
+
+static void
+model_changed (MemoEditor *me)
+{
+	if (!me->priv->updating) {
+		comp_editor_set_changed (COMP_EDITOR (me), TRUE);
+		comp_editor_set_needs_send (COMP_EDITOR (me), TRUE);
+	}	
+}
+
+static void
+model_row_change_insert_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+	model_changed (MEMO_EDITOR (data));
+}
+
+static void
+model_row_delete_cb (GtkTreeModel *model, GtkTreePath *path, gpointer data)
+{
+	model_changed (MEMO_EDITOR (data));
+}
Index: calendar/gui/dialogs/memo-editor.h
===================================================================
RCS file: calendar/gui/dialogs/memo-editor.h
diff -N calendar/gui/dialogs/memo-editor.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/dialogs/memo-editor.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,59 @@
+/* Evolution calendar - Task editor dialog
+ *
+ * Copyright (C) 2000 Ximian, Inc.
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Authors: Miguel de Icaza <miguel ximian com>
+ *          Federico Mena-Quintero <federico ximian com>
+ *          Seth Alves <alves hungry com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MEMO_EDITOR_H__
+#define __MEMO_EDITOR_H__
+
+#include <gtk/gtkobject.h>
+#include "comp-editor.h"
+
+#define TYPE_MEMO_EDITOR            (memo_editor_get_type ())
+#define MEMO_EDITOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MEMO_EDITOR, MemoEditor))
+#define MEMO_EDITOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MEMO_EDITOR,	\
+				      MemoEditorClass))
+#define IS_MEMO_EDITOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MEMO_EDITOR))
+#define IS_MEMO_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MEMO_EDITOR))
+
+typedef struct _MemoEditor MemoEditor;
+typedef struct _MemoEditorClass MemoEditorClass;
+typedef struct _MemoEditorPrivate MemoEditorPrivate;
+
+struct _MemoEditor {
+	CompEditor parent;
+
+	/* Private data */
+	MemoEditorPrivate *priv;
+};
+
+struct _MemoEditorClass {
+	CompEditorClass parent_class;
+};
+
+GtkType     memo_editor_get_type       (void);
+MemoEditor *memo_editor_construct      (MemoEditor *te,
+					ECal  *client);
+MemoEditor *memo_editor_new            (ECal  *client);
+
+
+#endif /* __MEMO_EDITOR_H__ */
Index: calendar/gui/dialogs/memo-page.c
===================================================================
RCS file: calendar/gui/dialogs/memo-page.c
diff -N calendar/gui/dialogs/memo-page.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/dialogs/memo-page.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,618 @@
+/* Evolution calendar - Main page of the memo editor dialog
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Authors: Federico Mena-Quintero <federico ximian com>
+ *          Miguel de Icaza <miguel ximian com>
+ *          Seth Alves <alves hungry com>
+ *          JP Rosevear <jpr ximian com>
+ *          Nathan Owens <pianocomp81 yahoo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtktextview.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkmessagedialog.h>
+#include <libgnome/gnome-i18n.h>
+#include <glade/glade.h>
+#include <libedataserverui/e-source-option-menu.h>
+#include <widgets/misc/e-dateedit.h>
+
+#include "common/authentication.h"
+#include "e-util/e-dialog-widgets.h"
+#include "e-util/e-categories-config.h"
+#include "../calendar-config.h"
+#include "comp-editor.h"
+#include "comp-editor-util.h"
+#include "e-send-options-utils.h"
+#include "memo-page.h"
+
+
+/* Private part of the TaskPage structure */
+struct _MemoPagePrivate {
+	/* Glade XML data */
+	GladeXML *xml;
+
+	/* Widgets from the Glade file */
+	GtkWidget *main;
+
+	GtkWidget *memo_content;
+
+	GtkWidget *classification;
+
+	GtkWidget *categories_btn;
+	GtkWidget *categories;
+
+	GtkWidget *source_selector;
+
+	gboolean updating;
+};
+
+static const int classification_map[] = {
+	E_CAL_COMPONENT_CLASS_PUBLIC,
+	E_CAL_COMPONENT_CLASS_PRIVATE,
+	E_CAL_COMPONENT_CLASS_CONFIDENTIAL,
+	-1
+};
+
+
+
+static void memo_page_finalize (GObject *object);
+
+static GtkWidget *memo_page_get_widget (CompEditorPage *page);
+static void memo_page_focus_main_widget (CompEditorPage *page);
+static gboolean memo_page_fill_widgets (CompEditorPage *page, ECalComponent *comp);
+static gboolean memo_page_fill_component (CompEditorPage *page, ECalComponent *comp);
+
+G_DEFINE_TYPE (MemoPage, memo_page, TYPE_COMP_EDITOR_PAGE);
+
+
+
+/**
+ * memo_page_get_type:
+ * 
+ * Registers the #TaskPage class if necessary, and returns the type ID
+ * associated to it.
+ * 
+ * Return value: The type ID of the #TaskPage class.
+ **/
+
+/* Class initialization function for the memo page */
+static void
+memo_page_class_init (MemoPageClass *klass)
+{
+	CompEditorPageClass *editor_page_class;
+	GObjectClass *object_class;
+
+	editor_page_class = (CompEditorPageClass *) klass;
+	object_class = (GObjectClass *) klass;
+
+	editor_page_class->get_widget = memo_page_get_widget;
+	editor_page_class->focus_main_widget = memo_page_focus_main_widget;
+	editor_page_class->fill_widgets = memo_page_fill_widgets;
+	editor_page_class->fill_component = memo_page_fill_component;
+	
+	object_class->finalize = memo_page_finalize;
+}
+
+/* Object initialization function for the memo page */
+static void
+memo_page_init (MemoPage *tpage)
+{
+	MemoPagePrivate *priv;
+
+	priv = g_new0 (MemoPagePrivate, 1);
+	tpage->priv = priv;
+
+	priv->xml = NULL;
+
+	priv->main = NULL;
+	priv->memo_content = NULL;
+	priv->classification = NULL;
+	priv->categories_btn = NULL;
+	priv->categories = NULL;
+
+	priv->updating = FALSE;
+}
+
+/* Destroy handler for the memo page */
+static void
+memo_page_finalize (GObject *object)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (IS_MEMO_PAGE (object));
+
+	tpage = MEMO_PAGE (object);
+	priv = tpage->priv;
+
+	if (priv->main)
+		gtk_widget_unref (priv->main);
+
+	if (priv->xml) {
+		g_object_unref (priv->xml);
+		priv->xml = NULL;
+	}
+
+	g_free (priv);
+	tpage->priv = NULL;
+
+	if (G_OBJECT_CLASS (memo_page_parent_class)->finalize)
+		(* G_OBJECT_CLASS (memo_page_parent_class)->finalize) (object);
+}
+
+
+
+/* get_widget handler for the task page */
+static GtkWidget *
+memo_page_get_widget (CompEditorPage *page)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+
+	tpage = MEMO_PAGE (page);
+	priv = tpage->priv;
+
+	return priv->main;
+}
+
+/* focus_main_widget handler for the memo page */
+static void
+memo_page_focus_main_widget (CompEditorPage *page)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+
+	tpage = MEMO_PAGE (page);
+	priv = tpage->priv;
+
+	gtk_widget_grab_focus (priv->memo_content);
+}
+
+/* Fills the widgets with default values */
+static void
+clear_widgets (MemoPage *tpage)
+{
+	MemoPagePrivate *priv;
+
+	priv = tpage->priv;
+
+	/* memo content */
+	gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)), "", 0);
+
+	/* Classification */
+	e_dialog_option_menu_set (priv->classification, E_CAL_COMPONENT_CLASS_PRIVATE, classification_map);
+
+	/* Categories */
+	e_dialog_editable_set (priv->categories, NULL);
+}
+
+/* Decode the radio button group for classifications */
+static ECalComponentClassification
+classification_get (GtkWidget *widget)
+{
+	return e_dialog_option_menu_get (widget, classification_map);
+}
+
+static void
+sensitize_widgets (MemoPage *mpage)
+{
+	gboolean read_only;
+	MemoPagePrivate *priv;
+	
+	priv = mpage->priv;
+
+	if (!e_cal_is_read_only (COMP_EDITOR_PAGE (mpage)->client, &read_only, NULL))
+		read_only = TRUE;
+	
+	gtk_widget_set_sensitive (priv->memo_content, !read_only);
+	gtk_widget_set_sensitive (priv->classification, !read_only);
+	gtk_widget_set_sensitive (priv->categories_btn, !read_only);
+	gtk_entry_set_editable (GTK_ENTRY (priv->categories), !read_only);
+}
+
+/* fill_widgets handler for the memo page */
+static gboolean
+memo_page_fill_widgets (CompEditorPage *page, ECalComponent *comp)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+	ECalComponentClassification cl;
+	GSList *l;
+	const char *categories;
+	ESource *source;
+
+	tpage = MEMO_PAGE (page);
+	priv = tpage->priv;
+
+	priv->updating = TRUE;
+	
+	/* Clean the screen */
+	clear_widgets (tpage);
+
+	e_cal_component_get_description_list (comp, &l);
+	if (l && l->data) {
+		ECalComponentText *dtext;
+		
+		dtext = l->data;
+		gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)),
+					  dtext->value ? dtext->value : "", -1);
+	} else {
+		gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)),
+					  "", 0);
+	}
+	e_cal_component_free_text_list (l);
+
+	/* Classification. */
+	e_cal_component_get_classification (comp, &cl);
+
+	switch (cl) {
+	case E_CAL_COMPONENT_CLASS_PUBLIC:
+	case E_CAL_COMPONENT_CLASS_PRIVATE:
+	case E_CAL_COMPONENT_CLASS_CONFIDENTIAL:
+		break;
+	default:
+		/* default to PUBLIC */
+		cl = E_CAL_COMPONENT_CLASS_PUBLIC;
+                break;
+	}
+	e_dialog_option_menu_set (priv->classification, cl, classification_map);
+
+	/* Categories */
+	e_cal_component_get_categories (comp, &categories);
+	e_dialog_editable_set (priv->categories, categories);
+
+	/* Source */
+	source = e_cal_get_source (page->client);
+	e_source_option_menu_select (E_SOURCE_OPTION_MENU (priv->source_selector), source);
+
+	priv->updating = FALSE;
+
+	sensitize_widgets (tpage);
+
+	return TRUE;
+}
+
+/* fill_component handler for the memo page */
+static gboolean
+memo_page_fill_component (CompEditorPage *page, ECalComponent *comp)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+	char *cat, *str;
+	int i;
+	GtkTextBuffer *text_buffer;
+	GtkTextIter text_iter_start, text_iter_end;
+
+	tpage = MEMO_PAGE (page);
+	priv = tpage->priv;
+	text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content));
+
+	/* Memo Content */
+
+	gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start);
+	gtk_text_buffer_get_end_iter   (text_buffer, &text_iter_end);
+	str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE);
+
+	if (!str || strlen (str) == 0){
+		e_cal_component_set_description_list (comp, NULL);
+		e_cal_component_set_summary(comp, NULL);
+	}
+	else {
+		int idxToUse = -1, nstr = strlen(str);
+		gboolean foundNL = FALSE;
+		GSList l;
+		ECalComponentText text, sumText;
+		char *txt;
+
+		for(i = 0; i<nstr && i<50; i++){
+			if(str[i] == '\n'){
+				idxToUse = i;
+				foundNL = TRUE;
+				break;
+			}
+		}
+		
+		if(foundNL == FALSE){
+			if(nstr > 50){
+				sumText.value = txt = g_strndup(str, 50);
+			}
+			else{
+				sumText.value = txt = g_strdup(str);
+			}
+		}
+		else{
+			sumText.value = txt = g_strndup(str, idxToUse); /* cuts off '\n' */
+		}
+		
+		sumText.altrep = NULL;
+
+		text.value = str;
+		text.altrep = NULL;
+		l.data = &text;
+		l.next = NULL;
+
+		e_cal_component_set_summary(comp, &sumText);
+		e_cal_component_set_description_list (comp, &l);
+		
+		g_free(txt);
+	}
+
+	if (str)
+		g_free (str);
+
+	/* Classification. */
+	e_cal_component_set_classification (comp, classification_get (priv->classification));
+
+	/* Categories */
+	cat = e_dialog_editable_get (priv->categories);
+	str = comp_editor_strip_categories (cat);
+	if (cat)
+		g_free (cat);
+
+	e_cal_component_set_categories (comp, str);
+
+	if (str)
+		g_free (str);
+
+	return TRUE;
+}
+
+
+
+
+/* Gets the widgets from the XML file and returns if they are all available. */
+static gboolean
+get_widgets (MemoPage *tpage)
+{
+	CompEditorPage *page = COMP_EDITOR_PAGE (tpage);
+	MemoPagePrivate *priv;
+	GSList *accel_groups;
+	GtkWidget *toplevel;
+
+	priv = tpage->priv;
+
+#define GW(name) glade_xml_get_widget (priv->xml, name)
+
+	priv->main = GW ("memo-page");
+	if (!priv->main){
+		g_warning("couldn't find memo-page!");
+		return FALSE;
+	}
+
+	/* Get the GtkAccelGroup from the toplevel window, so we can install
+	   it when the notebook page is mapped. */
+	toplevel = gtk_widget_get_toplevel (priv->main);
+	accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
+	if (accel_groups) {
+		page->accel_group = accel_groups->data;
+		gtk_accel_group_ref (page->accel_group);
+	}
+
+	gtk_widget_ref (priv->main);
+	gtk_container_remove (GTK_CONTAINER (priv->main->parent), priv->main);
+
+	priv->memo_content = GW ("memo_content");
+
+	priv->classification = GW ("classification");
+
+	priv->categories_btn = GW ("categories-button");
+	priv->categories = GW ("categories");
+
+	priv->source_selector = GW ("source");
+
+#undef GW
+
+	return (priv->classification
+		&& priv->memo_content
+		&& priv->categories_btn
+		&& priv->categories);
+}
+
+/* Callback used when the categories button is clicked; we must bring up the
+ * category list dialog.
+ */
+static void
+categories_clicked_cb (GtkWidget *button, gpointer data)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+	GtkWidget *entry;
+
+	tpage = MEMO_PAGE (data);
+	priv = tpage->priv;
+
+	entry = priv->categories;
+	e_categories_config_open_dialog_for_entry (GTK_ENTRY (entry));
+}
+
+/* This is called when any field is changed; it notifies upstream. */
+static void
+field_changed_cb (GtkWidget *widget, gpointer data)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+	
+	tpage = MEMO_PAGE (data);
+	priv = tpage->priv;
+	
+	if (!priv->updating)
+		comp_editor_page_notify_changed (COMP_EDITOR_PAGE (tpage));
+}
+
+static void
+source_changed_cb (GtkWidget *widget, ESource *source, gpointer data)
+{
+	MemoPage *tpage;
+	MemoPagePrivate *priv;
+
+	tpage = MEMO_PAGE (data);
+	priv = tpage->priv;
+
+	if (!priv->updating) {
+		ECal *client;
+
+		client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+		if (!client || !e_cal_open (client, FALSE, NULL)) {
+			GtkWidget *dialog;
+
+			if (client)
+				g_object_unref (client);
+
+			e_source_option_menu_select (E_SOURCE_OPTION_MENU (priv->source_selector),
+						     e_cal_get_source (COMP_EDITOR_PAGE (tpage)->client));
+
+			dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+							 GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+							 _("Unable to open memos in '%s'."),
+							 e_source_peek_name (source));
+			gtk_dialog_run (GTK_DIALOG (dialog));
+			gtk_widget_destroy (dialog);
+		} else {
+			comp_editor_notify_client_changed (
+				COMP_EDITOR (gtk_widget_get_toplevel (priv->main)),
+				client);
+			sensitize_widgets (tpage);
+		}
+	}
+}
+
+/* Hooks the widget signals */
+static gboolean
+init_widgets (MemoPage *tpage)
+{
+	MemoPagePrivate *priv;
+	GtkTextBuffer *text_buffer;
+
+	priv = tpage->priv;
+
+	/* Memo Content */
+	text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content));
+
+	gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->memo_content), GTK_WRAP_WORD);
+
+	/* Categories button */
+	g_signal_connect((priv->categories_btn), "clicked",
+			    G_CALLBACK (categories_clicked_cb), tpage);
+
+	/* Source selector */
+	g_signal_connect((priv->source_selector), "source_selected",
+			 G_CALLBACK (source_changed_cb), tpage);
+
+	/* Connect the default signal handler to use to make sure the "changed"
+	   field gets set whenever a field is changed. */
+
+	/* Belongs to priv->memo_content */
+	g_signal_connect ((text_buffer), "changed",
+			  G_CALLBACK (field_changed_cb), tpage);
+
+	g_signal_connect((priv->classification), "changed",
+			    G_CALLBACK (field_changed_cb), tpage);
+	g_signal_connect((priv->categories), "changed",
+			    G_CALLBACK (field_changed_cb), tpage);
+	
+	return TRUE;
+}
+
+
+/**
+ * memo_page_construct:
+ * @tpage: An memo page.
+ * 
+ * Constructs an memo page by loading its Glade data.
+ * 
+ * Return value: The same object as @tpage, or NULL if the widgets could not be
+ * created.
+ **/
+MemoPage *
+memo_page_construct (MemoPage *tpage)
+{
+	MemoPagePrivate *priv;
+
+	priv = tpage->priv;
+
+	priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/memo-page.glade",
+				   NULL, NULL);
+	if (!priv->xml) {
+		g_message ("memo_page_construct(): "
+			   "Could not load the Glade XML file!");
+		return NULL;
+	}
+
+	if (!get_widgets (tpage)) {
+		g_message ("memo_page_construct(): "
+			   "Could not find all widgets in the XML file!");
+		return NULL;
+	}
+
+	if (!init_widgets (tpage)) {
+		g_message ("memo_page_construct(): " 
+			   "Could not initialize the widgets!");
+		return NULL;
+	}
+
+	return tpage;
+}
+
+/**
+ * memo_page_new:
+ * 
+ * Creates a new memo page.
+ * 
+ * Return value: A newly-created task page, or NULL if the page could
+ * not be created.
+ **/
+MemoPage *
+memo_page_new (void)
+{
+	MemoPage *tpage;
+
+	tpage = gtk_type_new (TYPE_MEMO_PAGE);
+	if (!memo_page_construct (tpage)) {
+		g_object_unref (tpage);
+		return NULL;
+	}
+
+	return tpage;
+}
+
+GtkWidget *memo_page_create_source_option_menu (void);
+
+GtkWidget *
+memo_page_create_source_option_menu (void)
+{
+	GtkWidget   *menu;
+	GConfClient *gconf_client;
+	ESourceList *source_list;
+
+	gconf_client = gconf_client_get_default ();
+	source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/memos/sources");
+
+	menu = e_source_option_menu_new (source_list);
+	g_object_unref (source_list);
+
+	gtk_widget_show (menu);
+	return menu;
+}
Index: calendar/gui/dialogs/memo-page.glade
===================================================================
RCS file: calendar/gui/dialogs/memo-page.glade
diff -N calendar/gui/dialogs/memo-page.glade
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/dialogs/memo-page.glade	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,323 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd";>
+
+<glade-interface>
+
+<widget class="GtkWindow" id="memo-toplevel">
+  <property name="title" translatable="yes">window1</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+
+  <child>
+    <widget class="GtkVBox" id="memo-page">
+      <property name="border_width">12</property>
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">6</property>
+
+      <child>
+	<widget class="GtkLabel" id="label21">
+	  <property name="visible">True</property>
+	  <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Basics&lt;/span&gt;</property>
+	  <property name="use_underline">False</property>
+	  <property name="use_markup">True</property>
+	  <property name="justify">GTK_JUSTIFY_LEFT</property>
+	  <property name="wrap">False</property>
+	  <property name="selectable">False</property>
+	  <property name="xalign">0</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xpad">0</property>
+	  <property name="ypad">0</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHBox" id="hbox7">
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">0</property>
+
+	  <child>
+	    <widget class="GtkLabel" id="label22">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes"></property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">12</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkTable" id="table3">
+	      <property name="visible">True</property>
+	      <property name="n_rows">4</property>
+	      <property name="n_columns">2</property>
+	      <property name="homogeneous">False</property>
+	      <property name="row_spacing">6</property>
+	      <property name="column_spacing">12</property>
+	      
+	      <child>
+		<widget class="GtkLabel" id="label100">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Classi_fication:</property>
+		  <property name="use_underline">True</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="mnemonic_widget">classification</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">1</property>
+		  <property name="top_attach">1</property>
+		  <property name="bottom_attach">2</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox10">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkOptionMenu" id="classification">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="history">0</property>
+
+		      <child>
+			<widget class="GtkMenu" id="menu1">
+
+			  <child>
+			    <widget class="GtkMenuItem" id="public1">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">Public</property>
+			      <property name="use_underline">True</property>
+			    </widget>
+			  </child>
+
+			  <child>
+			    <widget class="GtkMenuItem" id="private1">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">Private</property>
+			      <property name="use_underline">True</property>
+			    </widget>
+			  </child>
+
+			  <child>
+			    <widget class="GtkMenuItem" id="confidential1">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">Confidential</property>
+			      <property name="use_underline">True</property>
+			    </widget>
+			  </child>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label23">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Group:</property>
+		      <property name="use_underline">True</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">12</property>
+		      <property name="ypad">0</property>
+		      <property name="mnemonic_widget">source</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="Custom" id="source">
+		      <property name="visible">True</property>
+		      <property name="creation_function">memo_page_create_source_option_menu</property>
+		      <property name="int1">0</property>
+		      <property name="int2">0</property>
+		      <property name="last_modification_time">Thu, 13 Jan 2004 22:00:00 GMT</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="left_attach">1</property>
+		  <property name="right_attach">2</property>
+		  <property name="top_attach">1</property>
+		  <property name="bottom_attach">2</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options">fill</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkButton" id="categories-button">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="label" translatable="yes">Ca_tegories...</property>
+		  <property name="use_underline">True</property>
+		  <property name="relief">GTK_RELIEF_NORMAL</property>
+		  <property name="focus_on_click">True</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">1</property>
+		  <property name="top_attach">2</property>
+		  <property name="bottom_attach">3</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkEntry" id="categories">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="editable">True</property>
+		  <property name="visibility">True</property>
+		  <property name="max_length">0</property>
+		  <property name="text" translatable="yes"></property>
+		  <property name="has_frame">True</property>
+		  <property name="invisible_char" translatable="yes">*</property>
+		  <property name="activates_default">False</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">1</property>
+		  <property name="right_attach">2</property>
+		  <property name="top_attach">2</property>
+		  <property name="bottom_attach">3</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkScrolledWindow" id="scrolledwindow1">
+		  <property name="visible">True</property>
+		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		  <property name="shadow_type">GTK_SHADOW_IN</property>
+		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+		  <child>
+		    <widget class="GtkTextView" id="memo_content">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="overwrite">False</property>
+		      <property name="accepts_tab">True</property>
+		      <property name="justification">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap_mode">GTK_WRAP_WORD</property>
+		      <property name="cursor_visible">True</property>
+		      <property name="pixels_above_lines">0</property>
+		      <property name="pixels_below_lines">0</property>
+		      <property name="pixels_inside_wrap">0</property>
+		      <property name="left_margin">0</property>
+		      <property name="right_margin">0</property>
+		      <property name="indent">0</property>
+		      <property name="text" translatable="yes"></property>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="left_attach">1</property>
+		  <property name="right_attach">2</property>
+		  <property name="top_attach">3</property>
+		  <property name="bottom_attach">4</property>
+		  <property name="x_options">expand|shrink|fill</property>
+		  <property name="y_options">expand|shrink|fill</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label18">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">_Memo Content:</property>
+		  <property name="use_underline">True</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_CENTER</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="mnemonic_widget">memo content</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">1</property>
+		  <property name="top_attach">3</property>
+		  <property name="bottom_attach">4</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options">fill</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">True</property>
+	      <property name="fill">True</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
Index: calendar/gui/dialogs/memo-page.h
===================================================================
RCS file: calendar/gui/dialogs/memo-page.h
diff -N calendar/gui/dialogs/memo-page.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/dialogs/memo-page.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,56 @@
+/* Evolution calendar - Main page of the memo editor dialog
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Authors: Federico Mena-Quintero <federico ximian com>
+ *          Miguel de Icaza <miguel ximian com>
+ *          Seth Alves <alves hungry com>
+ *          JP Rosevear <jpr ximian com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MEMO_PAGE_H
+#define MEMO_PAGE_H
+
+#include "comp-editor-page.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_MEMO_PAGE            (memo_page_get_type ())
+#define MEMO_PAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MEMO_PAGE, MemoPage))
+#define MEMO_PAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MEMO_PAGE, MemoPageClass))
+#define IS_MEMO_PAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MEMO_PAGE))
+#define IS_MEMO_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TYPE_MEMO_PAGE))
+
+typedef struct _MemoPagePrivate MemoPagePrivate;
+
+typedef struct {
+	CompEditorPage page;
+
+	/* Private data */
+	MemoPagePrivate *priv;
+} MemoPage;
+
+typedef struct {
+	CompEditorPageClass parent_class;
+} MemoPageClass;
+
+GtkType   memo_page_get_type  (void);
+MemoPage *memo_page_construct (MemoPage *epage);
+MemoPage *memo_page_new       (void);
+
+G_END_DECLS
+
+#endif
Index: ui/evolution-memos.xml
===================================================================
RCS file: ui/evolution-memos.xml
diff -N ui/evolution-memos.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ui/evolution-memos.xml	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,56 @@
+<Root>
+  <commands>
+    <cmd name="MemosOpenMemo" _tip="View the selected memo" accel="*Control*o"/>
+    <cmd name="MemosPrint" _tip="Print the list of memos" pixtype="stock" pixname="gtk-print"
+	 accel="*Control*p"/>
+    <cmd name="MemosPrintPreview" _tip="Previews the list of memos to be printed" pixtype="stock" pixname="gtk-print-preview"/>
+
+    <cmd name="MemosCut" _tip="Cut selected memo" accel="*Control*x" pixtype="stock" pixname="gtk-cut"/>
+    <cmd name="MemosCopy" _tip="Copy selected memo" accel="*Control*c" pixtype="stock" pixname="gtk-copy"/>
+    <cmd name="MemosPaste" _tip="Paste memo from the clipboard" accel="*Control*v" pixtype="stock" pixname="gtk-paste"/>
+    <cmd name="MemosDelete" _tip="Delete selected memos" accel="*Control*d" sensitive="0"
+         pixtype="stock" pixname="gtk-delete"/>
+
+  </commands>
+  
+  <menu>
+    <submenu name="File">
+      <placeholder name="FileOps">
+        <menuitem name="OpenMemo" verb="MemosOpenMemo" _label="_Open Memo"/>
+      </placeholder>
+      <placeholder name="Print">
+	<menuitem name="PrintPreview" verb="MemosPrintPreview" _label="Print Pre_view"/>
+
+	<menuitem name="Print" verb="MemosPrint" accel="*Control*p" _label="_Print..."/>
+      </placeholder>
+
+    </submenu>
+
+    <submenu name="Edit" _label="_Edit">
+      <placeholder name="EditPlaceholder">
+        <menuitem name="MemosCut" verb="" _label="C_ut"/>
+        <menuitem name="MemosCopy" verb="" _label="_Copy"/>
+        <menuitem name="MemosPaste" verb="" _label="_Paste"/>
+        
+		<separator/>
+        
+		<menuitem name="MemosDelete" verb="" _label="_Delete"/>
+      </placeholder>
+    </submenu>
+
+  </menu>
+
+  <dockitem name="Toolbar">
+    <toolitem name="Cut" _label="Cut" verb="MemosCut"/>
+    <toolitem name="Copy" _label="Copy" verb="MemosCopy"/>
+    <toolitem name="Paste" _label="Paste" verb="MemosPaste"/>
+
+    <separator/>
+
+    <toolitem name="Print" _label="Print" verb="MemosPrint"/>
+
+    <toolitem name="Delete" _label="Delete" verb="MemosDelete"/>
+
+  </dockitem>
+
+</Root>
Index: views/memos/Makefile.am
===================================================================
RCS file: views/memos/Makefile.am
diff -N views/memos/Makefile.am
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/memos/Makefile.am	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,3 @@
+memosviewsdir = $(viewsdir)/memos
+memosviews_DATA = Memos.galview galview.xml
+EXTRA_DIST = $(memosviews_DATA)
Index: views/memos/Memos.galview
===================================================================
RCS file: views/memos/Memos.galview
diff -N views/memos/Memos.galview
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/memos/Memos.galview	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<ETableState state-version="0.100000">
+  <column source="1"/>
+  <column source="0"/>
+  <column source="2"/>
+  <grouping></grouping>
+</ETableState>
Index: views/memos/galview.xml
===================================================================
RCS file: views/memos/galview.xml
diff -N views/memos/galview.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/memos/galview.xml	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<GalViewCollection default-view="Memos">
+  <GalView id="Memos" _title="_Memos" filename="Memos.galview" type="etable"/>
+</GalViewCollection>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]