aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui
diff options
context:
space:
mode:
authorHarish Krishnaswamy <kharish@novell.com>2005-10-19 19:39:35 +0800
committerHarish Krishnaswamy <kharish@src.gnome.org>2005-10-19 19:39:35 +0800
commit458df50352e58835c3a4fadff6705307dad39ab8 (patch)
treef6afd1b9b684909657dd078e089e2c6308c3b107 /calendar/gui
parentbf5eb927b690676631a8132cd8638ed5b0948b99 (diff)
downloadgsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.tar
gsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.tar.gz
gsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.tar.bz2
gsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.tar.lz
gsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.tar.xz
gsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.tar.zst
gsoc2013-evolution-458df50352e58835c3a4fadff6705307dad39ab8.zip
Memo Component - submitted by Nathan Owens <pianocomp81@yahoo.com>
2005-10-19 Harish Krishnaswamy <kharish@novell.com> Memo Component - submitted by Nathan Owens <pianocomp81@yahoo.com> svn path=/trunk/; revision=30537
Diffstat (limited to 'calendar/gui')
-rw-r--r--calendar/gui/GNOME_Evolution_Calendar.server.in.in20
-rw-r--r--calendar/gui/Makefile.am17
-rw-r--r--calendar/gui/calendar-config-keys.h5
-rw-r--r--calendar/gui/calendar-config.c49
-rw-r--r--calendar/gui/calendar-config.h11
-rw-r--r--calendar/gui/comp-util.c19
-rw-r--r--calendar/gui/comp-util.h1
-rw-r--r--calendar/gui/dialogs/Makefile.am7
-rw-r--r--calendar/gui/dialogs/calendar-setup.c79
-rw-r--r--calendar/gui/dialogs/calendar-setup.h3
-rw-r--r--calendar/gui/dialogs/memo-editor.c285
-rw-r--r--calendar/gui/dialogs/memo-editor.h59
-rw-r--r--calendar/gui/dialogs/memo-page.c618
-rw-r--r--calendar/gui/dialogs/memo-page.glade323
-rw-r--r--calendar/gui/dialogs/memo-page.h56
-rw-r--r--calendar/gui/dialogs/send-comp.c3
-rw-r--r--calendar/gui/e-cal-component-memo-preview.c374
-rw-r--r--calendar/gui/e-cal-component-memo-preview.h66
-rw-r--r--calendar/gui/e-cal-model-memos.c259
-rw-r--r--calendar/gui/e-cal-model-memos.h59
-rw-r--r--calendar/gui/e-memo-table-config.c241
-rw-r--r--calendar/gui/e-memo-table-config.h56
-rw-r--r--calendar/gui/e-memo-table.c1029
-rw-r--r--calendar/gui/e-memo-table.etspec13
-rw-r--r--calendar/gui/e-memo-table.h106
-rw-r--r--calendar/gui/e-memos.c1174
-rw-r--r--calendar/gui/e-memos.h87
-rw-r--r--calendar/gui/main.c6
-rw-r--r--calendar/gui/memos-component.c1330
-rw-r--r--calendar/gui/memos-component.h64
-rw-r--r--calendar/gui/memos-control.c361
-rw-r--r--calendar/gui/memos-control.h35
-rw-r--r--calendar/gui/migration.c120
-rw-r--r--calendar/gui/migration.h3
-rw-r--r--calendar/gui/print.c4
35 files changed, 6937 insertions, 5 deletions
diff --git a/calendar/gui/GNOME_Evolution_Calendar.server.in.in b/calendar/gui/GNOME_Evolution_Calendar.server.in.in
index 18c71798f0..f930ff9e72 100644
--- a/calendar/gui/GNOME_Evolution_Calendar.server.in.in
+++ b/calendar/gui/GNOME_Evolution_Calendar.server.in.in
@@ -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@">
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index 4225642d7d..5b854fd7cc 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -75,7 +75,8 @@ glade_DATA = \
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) \
@@ -103,6 +104,8 @@ libevolution_calendar_la_SOURCES = \
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 \
@@ -124,6 +127,8 @@ libevolution_calendar_la_SOURCES = \
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 \
@@ -165,6 +170,12 @@ libevolution_calendar_la_SOURCES = \
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 \
@@ -198,6 +209,10 @@ libevolution_calendar_la_SOURCES = \
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 \
diff --git a/calendar/gui/calendar-config-keys.h b/calendar/gui/calendar-config-keys.h
index eea70cfbcc..3a18e93d51 100644
--- a/calendar/gui/calendar-config-keys.h
+++ b/calendar/gui/calendar-config-keys.h
@@ -65,6 +65,11 @@ G_BEGIN_DECLS
#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"
diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c
index 8a33f6084c..bb6cb9e379 100644
--- a/calendar/gui/calendar-config.c
+++ b/calendar/gui/calendar-config.c
@@ -649,6 +649,55 @@ calendar_config_set_task_vpane_pos (gint vpane_pos)
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
diff --git a/calendar/gui/calendar-config.h b/calendar/gui/calendar-config.h
index 0a89b8a4fa..132e4af3ce 100644
--- a/calendar/gui/calendar-config.h
+++ b/calendar/gui/calendar-config.h
@@ -166,6 +166,17 @@ guint calendar_config_add_notification_primary_tasks (GConfClientNotifyFunc fu
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);
diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c
index 2be56453c1..fad01446da 100644
--- a/calendar/gui/comp-util.c
+++ b/calendar/gui/comp-util.c
@@ -369,3 +369,22 @@ cal_comp_task_new_with_defaults (ECal *client)
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;
+}
diff --git a/calendar/gui/comp-util.h b/calendar/gui/comp-util.h
index 26c7881e99..c57de4c692 100644
--- a/calendar/gui/comp-util.h
+++ b/calendar/gui/comp-util.h
@@ -42,5 +42,6 @@ gboolean cal_comp_is_on_server (ECalComponent *comp,
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
diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am
index e6b2b45434..b38b6223a2 100644
--- a/calendar/gui/dialogs/Makefile.am
+++ b/calendar/gui/dialogs/Makefile.am
@@ -51,6 +51,10 @@ libcal_dialogs_la_SOURCES = \
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 @@ libcal_dialogs_la_SOURCES = \
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 @@ glade_DATA = \
e-delegate-dialog.glade \
event-page.glade \
meeting-page.glade \
+ memo-page.glade \
recurrence-page.glade \
schedule-page.glade \
task-details-page.glade \
diff --git a/calendar/gui/dialogs/calendar-setup.c b/calendar/gui/dialogs/calendar-setup.c
index 3b6b578786..37b18d0d77 100644
--- a/calendar/gui/dialogs/calendar-setup.c
+++ b/calendar/gui/dialogs/calendar-setup.c
@@ -288,6 +288,8 @@ eccp_general_offline (EConfig *ec, EConfigItem *item, struct _GtkWidget *parent,
else if (sdialog->source_type == E_CAL_SOURCE_TYPE_TODO)
offline_setting = gtk_check_button_new_with_label (_("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(_("Copy memo list contents locally for offline operation"));
gtk_widget_show (offline_setting);
g_signal_connect (offline_setting, "toggled", G_CALLBACK (offline_status_changed_cb), sdialog);
@@ -383,6 +385,17 @@ static ECalConfigItem ectp_items[] = {
{ 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)
@@ -526,3 +539,69 @@ calendar_setup_new_task_list (struct _GtkWindow *parent)
{
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);
+}
diff --git a/calendar/gui/dialogs/calendar-setup.h b/calendar/gui/dialogs/calendar-setup.h
index 3e266df93c..0c4c272405 100644
--- a/calendar/gui/dialogs/calendar-setup.h
+++ b/calendar/gui/dialogs/calendar-setup.h
@@ -36,6 +36,9 @@ void calendar_setup_new_calendar (struct _GtkWindow *parent);
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
diff --git a/calendar/gui/dialogs/memo-editor.c b/calendar/gui/dialogs/memo-editor.c
new file mode 100644
index 0000000000..7946198e9b
--- /dev/null
+++ b/calendar/gui/dialogs/memo-editor.c
@@ -0,0 +1,285 @@
+/* -*- 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_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));
+}
diff --git a/calendar/gui/dialogs/memo-editor.h b/calendar/gui/dialogs/memo-editor.h
new file mode 100644
index 0000000000..79c86e9d4e
--- /dev/null
+++ b/calendar/gui/dialogs/memo-editor.h
@@ -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__ */
diff --git a/calendar/gui/dialogs/memo-page.c b/calendar/gui/dialogs/memo-page.c
new file mode 100644
index 0000000000..0a2644b699
--- /dev/null
+++ b/calendar/gui/dialogs/memo-page.c
@@ -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;
+}
diff --git a/calendar/gui/dialogs/memo-page.glade b/calendar/gui/dialogs/memo-page.glade
new file mode 100644
index 0000000000..2553e1a4f2
--- /dev/null
+++ b/calendar/gui/dialogs/memo-page.glade
@@ -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>
diff --git a/calendar/gui/dialogs/memo-page.h b/calendar/gui/dialogs/memo-page.h
new file mode 100644
index 0000000000..8df3b5ff65
--- /dev/null
+++ b/calendar/gui/dialogs/memo-page.h
@@ -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
diff --git a/calendar/gui/dialogs/send-comp.c b/calendar/gui/dialogs/send-comp.c
index f685bd1014..9e88f302eb 100644
--- a/calendar/gui/dialogs/send-comp.c
+++ b/calendar/gui/dialogs/send-comp.c
@@ -90,7 +90,8 @@ send_component_prompt_subject (GtkWindow *parent, ECal *client, ECalComponent *c
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);
diff --git a/calendar/gui/e-cal-component-memo-preview.c b/calendar/gui/e-cal-component-memo-preview.c
new file mode 100644
index 0000000000..4210f40a4c
--- /dev/null
+++ b/calendar/gui/e-cal-component-memo-preview.c
@@ -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));
+}
+
diff --git a/calendar/gui/e-cal-component-memo-preview.h b/calendar/gui/e-cal-component-memo-preview.h
new file mode 100644
index 0000000000..fb1716de63
--- /dev/null
+++ b/calendar/gui/e-cal-component-memo-preview.h
@@ -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_ */
diff --git a/calendar/gui/e-cal-model-memos.c b/calendar/gui/e-cal-model-memos.c
new file mode 100644
index 0000000000..d4cf6fc2b3
--- /dev/null
+++ b/calendar/gui/e-cal-model-memos.c
@@ -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);
+}
diff --git a/calendar/gui/e-cal-model-memos.h b/calendar/gui/e-cal-model-memos.h
new file mode 100644
index 0000000000..18ae106655
--- /dev/null
+++ b/calendar/gui/e-cal-model-memos.h
@@ -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
diff --git a/calendar/gui/e-memo-table-config.c b/calendar/gui/e-memo-table-config.c
new file mode 100644
index 0000000000..cb3ef06132
--- /dev/null
+++ b/calendar/gui/e-memo-table-config.c
@@ -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));
+}
diff --git a/calendar/gui/e-memo-table-config.h b/calendar/gui/e-memo-table-config.h
new file mode 100644
index 0000000000..f9a3f36cad
--- /dev/null
+++ b/calendar/gui/e-memo-table-config.h
@@ -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
diff --git a/calendar/gui/e-memo-table.c b/calendar/gui/e-memo-table.c
new file mode 100644
index 0000000000..906d61bba9
--- /dev/null
+++ b/calendar/gui/e-memo-table.c
@@ -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..."), NULL);
+ 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);
+ }
+}
diff --git a/calendar/gui/e-memo-table.etspec b/calendar/gui/e-memo-table.etspec
new file mode 100644
index 0000000000..06ecc2ce4b
--- /dev/null
+++ b/calendar/gui/e-memo-table.etspec
@@ -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>
diff --git a/calendar/gui/e-memo-table.h b/calendar/gui/e-memo-table.h
new file mode 100644
index 0000000000..da01405ac0
--- /dev/null
+++ b/calendar/gui/e-memo-table.h
@@ -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_ */
diff --git a/calendar/gui/e-memos.c b/calendar/gui/e-memos.c
new file mode 100644
index 0000000000..5825af0a43
--- /dev/null
+++ b/calendar/gui/e-memos.c
@@ -0,0 +1,1174 @@
+/* -*- 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));
+
+ 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);
+}
diff --git a/calendar/gui/e-memos.h b/calendar/gui/e-memos.h
new file mode 100644
index 0000000000..df4b6b1052
--- /dev/null
+++ b/calendar/gui/e-memos.h
@@ -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_ */
diff --git a/calendar/gui/main.c b/calendar/gui/main.c
index e8bfbafca3..44a880f120 100644
--- a/calendar/gui/main.c
+++ b/calendar/gui/main.c
@@ -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 @@ factory (BonoboGenericFactory *factory,
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)
diff --git a/calendar/gui/memos-component.c b/calendar/gui/memos-component.c
new file mode 100644
index 0000000000..ab9719f426
--- /dev/null
+++ b/calendar/gui/memos-component.c
@@ -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)
diff --git a/calendar/gui/memos-component.h b/calendar/gui/memos-component.h
new file mode 100644
index 0000000000..b8f60a96e4
--- /dev/null
+++ b/calendar/gui/memos-component.h
@@ -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_ */
diff --git a/calendar/gui/memos-control.c b/calendar/gui/memos-control.c
new file mode 100644
index 0000000000..040865aeaf
--- /dev/null
+++ b/calendar/gui/memos-control.c
@@ -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);
+}
+
diff --git a/calendar/gui/memos-control.h b/calendar/gui/memos-control.h
new file mode 100644
index 0000000000..52f5da9f39
--- /dev/null
+++ b/calendar/gui/memos-control.h
@@ -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_ */
diff --git a/calendar/gui/migration.c b/calendar/gui/migration.c
index bb63e8dd48..6118983130 100644
--- a/calendar/gui/migration.c
+++ b/calendar/gui/migration.c
@@ -997,3 +997,123 @@ fail:
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;
+}
diff --git a/calendar/gui/migration.h b/calendar/gui/migration.h
index 1092e30c14..5207dbe3b7 100644
--- a/calendar/gui/migration.h
+++ b/calendar/gui/migration.h
@@ -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
diff --git a/calendar/gui/print.c b/calendar/gui/print.c
index 717c9d2110..3930949269 100644
--- a/calendar/gui/print.c
+++ b/calendar/gui/print.c
@@ -2302,11 +2302,13 @@ print_comp_item (GnomePrintContext *pc, ECalComponent *comp, ECal *client,
vtype = e_cal_component_get_vtype (comp);
- /* We should only be asked to print VEVENTs or VTODOs. */
+ /* We should only be asked to print VEVENTs, VTODOs, or VJOURNALs. */
if (vtype == E_CAL_COMPONENT_EVENT)
title = _("Appointment");
else if (vtype == E_CAL_COMPONENT_TODO)
title = _("Task");
+ else if (vtype == E_CAL_COMPONENT_JOURNAL)
+ title = _("Memo");
else
return;