From 6375ba9a6cf327e665d98c5820992ab7fb80a6d0 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sat, 29 Nov 2008 15:26:50 +0000 Subject: Get drag-and-drop-to-source-selector working for contacts, memos and tasks. Utilizes the new ESourceSelector::data-dropped signal. svn path=/branches/kill-bonobo/; revision=36822 --- calendar/gui/Makefile.am | 4 + calendar/gui/e-calendar-selector.c | 155 ++--------------- calendar/gui/e-memo-list-selector.c | 287 +++++++++++++++++++++++++++++++ calendar/gui/e-memo-list-selector.h | 71 ++++++++ calendar/gui/e-memos.c | 120 ------------- calendar/gui/e-task-list-selector.c | 288 ++++++++++++++++++++++++++++++++ calendar/gui/e-task-list-selector.h | 71 ++++++++ calendar/modules/e-cal-shell-content.c | 1 + calendar/modules/e-memo-shell-content.c | 70 +++++++- calendar/modules/e-memo-shell-sidebar.c | 4 +- calendar/modules/e-task-shell-content.c | 68 +++++++- calendar/modules/e-task-shell-sidebar.c | 4 +- 12 files changed, 876 insertions(+), 267 deletions(-) create mode 100644 calendar/gui/e-memo-list-selector.c create mode 100644 calendar/gui/e-memo-list-selector.h create mode 100644 calendar/gui/e-task-list-selector.c create mode 100644 calendar/gui/e-task-list-selector.h (limited to 'calendar') diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index b371ec263b..cf514f251e 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -133,6 +133,8 @@ libcal_gui_la_SOURCES = \ e-meeting-types.h \ e-meeting-utils.c \ e-meeting-utils.h \ + e-memo-list-selector.c \ + e-memo-list-selector.h \ e-memo-table.c \ e-memo-table.h \ e-memo-table-config.c \ @@ -143,6 +145,8 @@ libcal_gui_la_SOURCES = \ e-select-names-editable.h \ e-select-names-renderer.c \ e-select-names-renderer.h \ + e-task-list-selector.c \ + e-task-list-selector.h \ e-week-view-config.c \ e-week-view-config.h \ e-week-view-event-item.c \ diff --git a/calendar/gui/e-calendar-selector.c b/calendar/gui/e-calendar-selector.c index 2fecc2eeca..54858e56f9 100644 --- a/calendar/gui/e-calendar-selector.c +++ b/calendar/gui/e-calendar-selector.c @@ -103,129 +103,16 @@ calendar_selector_update_objects (ECal *client, return TRUE; } -static void -calendar_selector_drag_leave (GtkWidget *widget, - GdkDragContext *context, - guint time_) -{ - /* XXX This is exactly the same as in EAddressbookSelector. - * Consider merging this callback into ESourceSelector. */ - - GtkTreeView *tree_view; - GtkTreeViewDropPosition pos; - - tree_view = GTK_TREE_VIEW (widget); - pos = GTK_TREE_VIEW_DROP_BEFORE; - - gtk_tree_view_set_drag_dest_row (tree_view, NULL, pos); -} - static gboolean -calendar_selector_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time_) +calendar_selector_data_dropped (ESourceSelector *selector, + GtkSelectionData *selection_data, + ESource *destination, + GdkDragAction action, + guint info) { - /* XXX This is exactly the same as in EAddressbookSelector. - * Consider merging this callback into ESourceSelector. */ - GtkTreeView *tree_view; GtkTreeModel *model; GtkTreePath *path = NULL; - GtkTreeIter iter; - GtkTreeViewDropPosition pos; - GdkDragAction action = 0; - gpointer object; - - tree_view = GTK_TREE_VIEW (widget); - model = gtk_tree_view_get_model (tree_view); - - if (!gtk_tree_view_get_dest_row_at_pos (tree_view, x, y, &path, NULL)) - goto exit; - - if (!gtk_tree_model_get_iter (model, &iter, path)) - goto exit; - - gtk_tree_model_get (model, &iter, 0, &object, -1); - - if (E_IS_SOURCE_GROUP (object) || e_source_get_readonly (object)) - goto exit; - - pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE; - gtk_tree_view_set_drag_dest_row (tree_view, path, pos); - - if (context->actions & GDK_ACTION_MOVE) - action = GDK_ACTION_MOVE; - else - action = context->suggested_action; - -exit: - if (path != NULL) - gtk_tree_path_free (path); - - if (object != NULL) - g_object_unref (object); - - gdk_drag_status (context, action, time_); - - return TRUE; -} - -static gboolean -calendar_selector_drag_drop (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time_) -{ - /* XXX This is exactly the same as in EAddressbookSelector. - * Consider merging this callback into ESourceSelector. */ - - GtkTreeView *tree_view; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - gboolean drop_zone; - gboolean valid; - gpointer object; - - tree_view = GTK_TREE_VIEW (widget); - model = gtk_tree_view_get_model (tree_view); - - if (!gtk_tree_view_get_path_at_pos ( - tree_view, x, y, &path, NULL, NULL, NULL)) - return FALSE; - - valid = gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - g_return_val_if_fail (valid, FALSE); - - gtk_tree_model_get (model, &iter, 0, &object, -1); - drop_zone = E_IS_SOURCE (object); - g_object_unref (object); - - return drop_zone; -} - -static void -calendar_selector_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint time_) -{ - /* XXX This is NEARLY the same as in EAddressbookSelector. - * Consider merging this callback into ESourceSelector. - * Use a callback to allow subclasses to handle the - * received selection data. */ - - GtkTreeView *tree_view; - GtkTreeModel *model; - GtkTreePath *path = NULL; - GtkTreeIter iter; ECal *client; icalcomponent *icalcomp; const gchar *string; @@ -233,22 +120,11 @@ calendar_selector_drag_data_received (GtkWidget *widget, gboolean success = FALSE; gpointer object = NULL; - tree_view = GTK_TREE_VIEW (widget); + tree_view = GTK_TREE_VIEW (selector); model = gtk_tree_view_get_model (tree_view); string = (const gchar *) selection_data->data; - remove_from_source = (context->action == GDK_ACTION_MOVE); - - if (!gtk_tree_view_get_dest_row_at_pos (tree_view, x, y, &path, NULL)) - goto exit; - - if (!gtk_tree_model_get_iter (model, &iter, path)) - goto exit; - - gtk_tree_model_get (model, &iter, 0, &object, -1); - - if (!E_IS_SOURCE (object) || e_source_get_readonly (object)) - goto exit; + remove_from_source = (action == GDK_ACTION_MOVE); icalcomp = icalparser_parse_string (string); @@ -256,7 +132,7 @@ calendar_selector_drag_data_received (GtkWidget *widget, goto exit; /* FIXME Deal with GDK_ACTION_ASK. */ - if (context->action == GDK_ACTION_COPY) { + if (action == GDK_ACTION_COPY) { gchar *uid; uid = e_cal_component_gen_uid (); @@ -264,7 +140,7 @@ calendar_selector_drag_data_received (GtkWidget *widget, } client = auth_new_cal_from_source ( - E_SOURCE (object), E_CAL_SOURCE_TYPE_EVENT); + destination, E_CAL_SOURCE_TYPE_EVENT); if (client != NULL) { if (e_cal_open (client, TRUE, NULL)) { @@ -277,6 +153,8 @@ calendar_selector_drag_data_received (GtkWidget *widget, icalcomponent_free (icalcomp); + success = TRUE; + exit: if (path != NULL) gtk_tree_path_free (path); @@ -284,22 +162,19 @@ exit: if (object != NULL) g_object_unref (object); - gtk_drag_finish (context, success, remove_from_source, time_); + return TRUE; } static void calendar_selector_class_init (ECalendarSelectorClass *class) { - GtkWidgetClass *widget_class; + ESourceSelectorClass *source_selector_class; parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (ECalendarSelectorPrivate)); - widget_class = GTK_WIDGET_CLASS (class); - widget_class->drag_leave = calendar_selector_drag_leave; - widget_class->drag_motion = calendar_selector_drag_motion; - widget_class->drag_drop = calendar_selector_drag_drop; - widget_class->drag_data_received = calendar_selector_drag_data_received; + source_selector_class = E_SOURCE_SELECTOR_CLASS (class); + source_selector_class->data_dropped = calendar_selector_data_dropped; } static void diff --git a/calendar/gui/e-memo-list-selector.c b/calendar/gui/e-memo-list-selector.c new file mode 100644 index 0000000000..9d3408944b --- /dev/null +++ b/calendar/gui/e-memo-list-selector.c @@ -0,0 +1,287 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-memo-list-selector.c + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "e-memo-list-selector.h" + +#include +#include +#include "calendar/common/authentication.h" +#include "calendar/gui/comp-util.h" + +#define E_MEMO_LIST_SELECTOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorPrivate)) + +struct _EMemoListSelectorPrivate { + gint dummy_value; +}; + +enum { + DND_TARGET_TYPE_CALENDAR_LIST +}; + +static GtkTargetEntry drag_types[] = { + { "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }, + { "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST } +}; + +static gpointer parent_class; + +static gboolean +memo_list_selector_update_single_object (ECal *client, + icalcomponent *icalcomp) +{ + gchar *uid; + icalcomponent *tmp_icalcomp; + + uid = (gchar *) 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 +memo_list_selector_update_objects (ECal *client, + icalcomponent *icalcomp) +{ + icalcomponent *subcomp; + icalcomponent_kind kind; + + kind = icalcomponent_isa (icalcomp); + if (kind == ICAL_VJOURNAL_COMPONENT) + return memo_list_selector_update_single_object ( + client, icalcomp); + else if (kind != ICAL_VCALENDAR_COMPONENT) + return FALSE; + + subcomp = icalcomponent_get_first_component ( + icalcomp, ICAL_ANY_COMPONENT); + while (subcomp != NULL) { + 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 FALSE; + } else if (kind == ICAL_VJOURNAL_COMPONENT) { + success = memo_list_selector_update_single_object ( + client, subcomp); + if (!success) + return FALSE; + } + + subcomp = icalcomponent_get_next_component ( + icalcomp, ICAL_ANY_COMPONENT); + } + + return TRUE; +} + +static gboolean +memo_list_selector_process_data (ESourceSelector *selector, + ECal *client, + const gchar *source_uid, + icalcomponent *icalcomp, + GdkDragAction action) +{ + ESourceList *source_list; + ESource *source; + icalcomponent *tmp_icalcomp = NULL; + const gchar *uid; + gchar *old_uid = NULL; + gboolean success = FALSE; + gboolean read_only = TRUE; + GError *error = NULL; + + /* FIXME Deal with GDK_ACTION_ASK. */ + if (action == GDK_ACTION_COPY) { + old_uid = g_strdup (icalcomponent_get_uid (icalcomp)); + uid = e_cal_component_gen_uid (); + icalcomponent_set_uid (icalcomp, uid); + } + + uid = icalcomponent_get_uid (icalcomp); + if (old_uid == NULL) + old_uid = g_strdup (uid); + + if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, &error)) { + icalcomponent_free (tmp_icalcomp); + success = TRUE; + goto exit; + } + + if (error != NULL && error->code != E_CALENDAR_STATUS_OBJECT_NOT_FOUND) { + g_message ( + "Failed to search the object in destination " + "task list: %s", error->message); + g_error_free (error); + goto exit; + } + + success = memo_list_selector_update_objects (client, icalcomp); + + if (!success || action != GDK_ACTION_MOVE) + goto exit; + + source_list = e_source_selector_get_source_list (selector); + source = e_source_list_peek_source_by_uid (source_list, source_uid); + + if (!E_IS_SOURCE (source) || e_source_get_readonly (source)) + goto exit; + + client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL); + if (client == NULL) { + g_message ("Cannot create source client to remove old memo"); + goto exit; + } + + e_cal_is_read_only (client, &read_only, NULL); + if (!read_only && e_cal_open (client, TRUE, NULL)) + e_cal_remove_object (client, old_uid, NULL); + else if (!read_only) + g_message ("Cannot open source client to remove old memo"); + + g_object_unref (client); + +exit: + g_free (old_uid); + + return success; +} + +static gboolean +memo_list_selector_data_dropped (ESourceSelector *selector, + GtkSelectionData *selection_data, + ESource *destination, + GdkDragAction action, + guint info) +{ + ECal *client; + GSList *list, *iter; + gboolean success = FALSE; + + client = auth_new_cal_from_source ( + destination, E_CAL_SOURCE_TYPE_JOURNAL); + + if (client == NULL || !e_cal_open (client, TRUE, NULL)) + goto exit; + + list = cal_comp_selection_get_string_list (selection_data); + + for (iter = list; iter != NULL; iter = iter->next) { + gchar *source_uid = iter->data; + icalcomponent *icalcomp; + gchar *component_string; + + /* Each string is "source_uid\ncomponent_string". */ + component_string = strchr (source_uid, '\n'); + if (component_string == NULL) + continue; + + *component_string++ = '\0'; + icalcomp = icalparser_parse_string (component_string); + if (icalcomp == NULL) + continue; + + success = memo_list_selector_process_data ( + selector, client, source_uid, icalcomp, action); + + icalcomponent_free (icalcomp); + } + + g_slist_foreach (list, (GFunc) g_free, NULL); + g_slist_free (list); + +exit: + if (client != NULL) + g_object_unref (client); + + return success; +} + +static void +memo_list_selector_class_init (EMemoListSelectorClass *class) +{ + ESourceSelectorClass *source_selector_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EMemoListSelectorPrivate)); + + source_selector_class = E_SOURCE_SELECTOR_CLASS (class); + source_selector_class->data_dropped = memo_list_selector_data_dropped; +} + +static void +memo_list_selector_init (EMemoListSelector *selector) +{ + selector->priv = E_MEMO_LIST_SELECTOR_GET_PRIVATE (selector); + + gtk_drag_dest_set ( + GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL, + drag_types, G_N_ELEMENTS (drag_types), + GDK_ACTION_COPY | GDK_ACTION_MOVE); +} + +GType +e_memo_list_selector_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EMemoListSelectorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) memo_list_selector_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMemoListSelector), + 0, /* n_preallocs */ + (GInstanceInitFunc) memo_list_selector_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_SOURCE_SELECTOR, "EMemoListSelector", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_memo_list_selector_new (ESourceList *source_list) +{ + g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL); + + return g_object_new ( + E_TYPE_MEMO_LIST_SELECTOR, + "source-list", source_list, NULL); +} diff --git a/calendar/gui/e-memo-list-selector.h b/calendar/gui/e-memo-list-selector.h new file mode 100644 index 0000000000..c10cff2a2e --- /dev/null +++ b/calendar/gui/e-memo-list-selector.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-memo-list-selector.h + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* XXX This widget is nearly identical to ETaskListSelector. If + * ECalendarSelector ever learns how to move selections from + * one source to another, perhaps these ESourceSelector sub- + * classes could someday be combined. */ + +#ifndef E_MEMO_LIST_SELECTOR_H +#define E_MEMO_LIST_SELECTOR_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MEMO_LIST_SELECTOR \ + (e_memo_list_selector_get_type ()) +#define E_MEMO_LIST_SELECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelector)) +#define E_MEMO_LIST_SELECTOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorClass)) +#define E_IS_MEMO_LIST_SELECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MEMO_LIST_SELECTOR)) +#define E_IS_MEMO_LIST_SELECTOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MEMO_LIST_SELECTOR)) +#define E_MEMO_LIST_SELECTOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorClass)) + +G_BEGIN_DECLS + +typedef struct _EMemoListSelector EMemoListSelector; +typedef struct _EMemoListSelectorClass EMemoListSelectorClass; +typedef struct _EMemoListSelectorPrivate EMemoListSelectorPrivate; + +struct _EMemoListSelector { + ESourceSelector parent; + EMemoListSelectorPrivate *priv; +}; + +struct _EMemoListSelectorClass { + ESourceSelectorClass parent_class; +}; + +GType e_memo_list_selector_get_type (void); +GtkWidget * e_memo_list_selector_new (ESourceList *source_list); + +G_END_DECLS + +#endif /* E_MEMO_LIST_SELECTOR_H */ diff --git a/calendar/gui/e-memos.c b/calendar/gui/e-memos.c index 99e9fb2e18..04efd14dd1 100644 --- a/calendar/gui/e-memos.c +++ b/calendar/gui/e-memos.c @@ -193,126 +193,6 @@ setup_config (EMemos *memos) priv->notifications = g_list_prepend (priv->notifications, GUINT_TO_POINTER (not)); } -struct AffectedComponents { - EMemoTable *memo_table; - GSList *components; /* contains pointers to ECalModelComponent */ -}; - -/** - * get_selected_components_cb - * Helper function to fill list of selected components in EMemoTable. - * This function is called from e_table_selected_row_foreach. - **/ -static void -get_selected_components_cb (int model_row, gpointer data) -{ - struct AffectedComponents *ac = (struct AffectedComponents *) data; - - if (!ac || !ac->memo_table) - return; - - ac->components = g_slist_prepend (ac->components, e_cal_model_get_component_at (E_CAL_MODEL (e_memo_table_get_model (ac->memo_table)), model_row)); -} - -/** - * do_for_selected_components - * Calls function func for all selected components in memo_table. - * - * @param memo_table Table with selected components of our interest. - * @param func Function to be called on each selected component from cal_table. - * The first parameter of this function is a pointer to ECalModelComponent and - * the second parameter of this function is pointer to cal_table - * @param user_data User data, will be passed to func. - **/ -static void -do_for_selected_components (EMemoTable *memo_table, GFunc func, gpointer user_data) -{ - ETable *etable; - struct AffectedComponents ac; - - g_return_if_fail (memo_table != NULL); - - ac.memo_table = memo_table; - ac.components = NULL; - - etable = e_table_scrolled_get_table (E_TABLE_SCROLLED (memo_table->etable)); - e_table_selected_row_foreach (etable, get_selected_components_cb, &ac); - - g_slist_foreach (ac.components, func, user_data); - g_slist_free (ac.components); -} - -/** - * obtain_list_of_components - * As a callback function to convert each ECalModelComponent to string - * of format "source_uid\ncomponent_str" and add this newly allocated - * string to the list of components. Strings should be freed with g_free. - * - * @param data ECalModelComponent object. - * @param user_data Pointer to GSList list, where to put new strings. - **/ -static void -obtain_list_of_components (gpointer data, gpointer user_data) -{ - GSList **list; - ECalModelComponent *comp_data; - - list = (GSList **) user_data; - comp_data = (ECalModelComponent *) data; - - if (list && comp_data) { - 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) { - ESource *source = e_cal_get_source (comp_data->client); - const char *source_uid = e_source_peek_uid (source); - - *list = g_slist_prepend (*list, g_strdup_printf ("%s\n%s", source_uid, comp_str)); - - /* do not free this pointer, it owns libical */ - /* g_free (comp_str); */ - } - - icalcomponent_free (vcal); - g_free (comp_str); - } -} - -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; - - priv = memos->priv; - - if (info == TARGET_VCALENDAR) { - /* we will pass an icalcalendar component for both types */ - GSList *components = NULL; - - do_for_selected_components (E_MEMO_TABLE (priv->memos_view), obtain_list_of_components, &components); - - if (components) { - cal_comp_selection_set_string_list (selection_data, components); - - g_slist_foreach (components, (GFunc)g_free, NULL); - g_slist_free (components); - } - } -} - static void setup_widgets (EMemos *memos) { diff --git a/calendar/gui/e-task-list-selector.c b/calendar/gui/e-task-list-selector.c new file mode 100644 index 0000000000..910ab3f33f --- /dev/null +++ b/calendar/gui/e-task-list-selector.c @@ -0,0 +1,288 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-task-list-selector.c + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "e-task-list-selector.h" + +#include +#include +#include "calendar/common/authentication.h" +#include "calendar/gui/comp-util.h" + +#define E_TASK_LIST_SELECTOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorPrivate)) + +struct _ETaskListSelectorPrivate { + gint dummy_value; +}; + +enum { + DND_TARGET_TYPE_CALENDAR_LIST +}; + +static GtkTargetEntry drag_types[] = { + { "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }, + { "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST } +}; + +static gpointer parent_class; + +static gboolean +task_list_selector_update_single_object (ECal *client, + icalcomponent *icalcomp) +{ + gchar *uid; + icalcomponent *tmp_icalcomp; + + uid = (gchar *) 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 +task_list_selector_update_objects (ECal *client, + icalcomponent *icalcomp) +{ + icalcomponent *subcomp; + icalcomponent_kind kind; + + kind = icalcomponent_isa (icalcomp); + if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT) + return task_list_selector_update_single_object ( + client, icalcomp); + else if (kind != ICAL_VCALENDAR_COMPONENT) + return FALSE; + + subcomp = icalcomponent_get_first_component ( + icalcomp, ICAL_ANY_COMPONENT); + while (subcomp != NULL) { + 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 FALSE; + } else if (kind == ICAL_VTODO_COMPONENT || + kind == ICAL_VEVENT_COMPONENT) { + success = task_list_selector_update_single_object ( + client, subcomp); + if (!success) + return FALSE; + } + + subcomp = icalcomponent_get_next_component ( + icalcomp, ICAL_ANY_COMPONENT); + } + + return TRUE; +} + +static gboolean +task_list_selector_process_data (ESourceSelector *selector, + ECal *client, + const gchar *source_uid, + icalcomponent *icalcomp, + GdkDragAction action) +{ + ESourceList *source_list; + ESource *source; + icalcomponent *tmp_icalcomp = NULL; + const gchar *uid; + gchar *old_uid = NULL; + gboolean success = FALSE; + gboolean read_only = TRUE; + GError *error = NULL; + + /* FIXME Deal with GDK_ACTION_ASK. */ + if (action == GDK_ACTION_COPY) { + old_uid = g_strdup (icalcomponent_get_uid (icalcomp)); + uid = e_cal_component_gen_uid (); + icalcomponent_set_uid (icalcomp, uid); + } + + uid = icalcomponent_get_uid (icalcomp); + if (old_uid == NULL) + old_uid = g_strdup (uid); + + if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, &error)) { + icalcomponent_free (tmp_icalcomp); + success = TRUE; + goto exit; + } + + if (error != NULL && error->code != E_CALENDAR_STATUS_OBJECT_NOT_FOUND) { + g_message ( + "Failed to search the object in destination " + "task list: %s", error->message); + g_error_free (error); + goto exit; + } + + success = task_list_selector_update_objects (client, icalcomp); + + if (!success || action != GDK_ACTION_MOVE) + goto exit; + + source_list = e_source_selector_get_source_list (selector); + source = e_source_list_peek_source_by_uid (source_list, source_uid); + + if (!E_IS_SOURCE (source) || e_source_get_readonly (source)) + goto exit; + + client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO); + if (client == NULL) { + g_message ("Cannot create source client to remove old task"); + goto exit; + } + + e_cal_is_read_only (client, &read_only, NULL); + if (!read_only && e_cal_open (client, TRUE, NULL)) + e_cal_remove_object (client, old_uid, NULL); + else if (!read_only) + g_message ("Cannot open source client to remove old task"); + + g_object_unref (client); + +exit: + g_free (old_uid); + + return success; +} + +static gboolean +task_list_selector_data_dropped (ESourceSelector *selector, + GtkSelectionData *selection_data, + ESource *destination, + GdkDragAction action, + guint info) +{ + ECal *client; + GSList *list, *iter; + gboolean success = FALSE; + + client = auth_new_cal_from_source ( + destination, E_CAL_SOURCE_TYPE_TODO); + + if (client == NULL || !e_cal_open (client, TRUE, NULL)) + goto exit; + + list = cal_comp_selection_get_string_list (selection_data); + + for (iter = list; iter != NULL; iter = iter->next) { + gchar *source_uid = iter->data; + icalcomponent *icalcomp; + gchar *component_string; + + /* Each string is "source_uid\ncomponent_string". */ + component_string = strchr (source_uid, '\n'); + if (component_string == NULL) + continue; + + *component_string++ = '\0'; + icalcomp = icalparser_parse_string (component_string); + if (icalcomp == NULL) + continue; + + success = task_list_selector_process_data ( + selector, client, source_uid, icalcomp, action); + + icalcomponent_free (icalcomp); + } + + g_slist_foreach (list, (GFunc) g_free, NULL); + g_slist_free (list); + +exit: + if (client != NULL) + g_object_unref (client); + + return success; +} + +static void +task_list_selector_class_init (ETaskListSelectorClass *class) +{ + ESourceSelectorClass *source_selector_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ETaskListSelectorPrivate)); + + source_selector_class = E_SOURCE_SELECTOR_CLASS (class); + source_selector_class->data_dropped = task_list_selector_data_dropped; +} + +static void +task_list_selector_init (ETaskListSelector *selector) +{ + selector->priv = E_TASK_LIST_SELECTOR_GET_PRIVATE (selector); + + gtk_drag_dest_set ( + GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL, + drag_types, G_N_ELEMENTS (drag_types), + GDK_ACTION_COPY | GDK_ACTION_MOVE); +} + +GType +e_task_list_selector_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (ETaskListSelectorClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) task_list_selector_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ETaskListSelector), + 0, /* n_preallocs */ + (GInstanceInitFunc) task_list_selector_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_SOURCE_SELECTOR, "ETaskListSelector", + &type_info, 0); + } + + return type; +} + +GtkWidget * +e_task_list_selector_new (ESourceList *source_list) +{ + g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL); + + return g_object_new ( + E_TYPE_TASK_LIST_SELECTOR, + "source-list", source_list, NULL); +} diff --git a/calendar/gui/e-task-list-selector.h b/calendar/gui/e-task-list-selector.h new file mode 100644 index 0000000000..847a221ba4 --- /dev/null +++ b/calendar/gui/e-task-list-selector.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-task-list-selector.h + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* XXX This widget is nearly identical to EMemoListSelector. If + * ECalendarSelector ever learns how to move selections from + * one source to another, perhaps these ESourceSelector sub- + * classes could someday be combined. */ + +#ifndef E_TASK_LIST_SELECTOR_H +#define E_TASK_LIST_SELECTOR_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_TASK_LIST_SELECTOR \ + (e_task_list_selector_get_type ()) +#define E_TASK_LIST_SELECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelector)) +#define E_TASK_LIST_SELECTOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorClass)) +#define E_IS_TASK_LIST_SELECTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_TASK_LIST_SELECTOR)) +#define E_IS_TASK_LIST_SELECTOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_TASK_LIST_SELECTOR)) +#define E_TASK_LIST_SELECTOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorClass)) + +G_BEGIN_DECLS + +typedef struct _ETaskListSelector ETaskListSelector; +typedef struct _ETaskListSelectorClass ETaskListSelectorClass; +typedef struct _ETaskListSelectorPrivate ETaskListSelectorPrivate; + +struct _ETaskListSelector { + ESourceSelector parent; + ETaskListSelectorPrivate *priv; +}; + +struct _ETaskListSelectorClass { + ESourceSelectorClass parent_class; +}; + +GType e_task_list_selector_get_type (void); +GtkWidget * e_task_list_selector_new (ESourceList *source_list); + +G_END_DECLS + +#endif /* E_TASK_LIST_SELECTOR_H */ diff --git a/calendar/modules/e-cal-shell-content.c b/calendar/modules/e-cal-shell-content.c index 80b989f64d..cc1f1ca879 100644 --- a/calendar/modules/e-cal-shell-content.c +++ b/calendar/modules/e-cal-shell-content.c @@ -21,6 +21,7 @@ #include "e-cal-shell-content.h" +#include #include #include "e-util/gconf-bridge.h" diff --git a/calendar/modules/e-memo-shell-content.c b/calendar/modules/e-memo-shell-content.c index 82495f836b..006e988c41 100644 --- a/calendar/modules/e-memo-shell-content.c +++ b/calendar/modules/e-memo-shell-content.c @@ -26,6 +26,7 @@ #include "e-util/gconf-bridge.h" #include "calendar/gui/calendar-config.h" +#include "calendar/gui/comp-util.h" #include "calendar/gui/e-cal-model-memos.h" #include "calendar/gui/e-memo-table.h" #include "calendar/gui/e-memo-table-config.h" @@ -90,6 +91,45 @@ memo_shell_content_display_view_cb (EMemoShellContent *memo_shell_content, gal_view_etable_attach_table (GAL_VIEW_ETABLE (gal_view), table); } +static void +memo_shell_content_table_foreach_cb (gint model_row, + gpointer user_data) +{ + ECalModelComponent *comp_data; + icalcomponent *clone; + icalcomponent *vcal; + gchar *string; + + struct { + ECalModel *model; + GSList *list; + } *foreach_data = user_data; + + comp_data = e_cal_model_get_component_at ( + foreach_data->model, model_row); + + vcal = e_cal_util_new_top_level (); + clone = icalcomponent_new_clone (comp_data->icalcomp); + e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp); + icalcomponent_add_component (vcal, clone); + + /* String is owned by libical; do not free. */ + string = icalcomponent_as_ical_string (vcal); + if (string != NULL) { + ESource *source; + const gchar *source_uid; + + source = e_cal_get_source (comp_data->client); + source_uid = e_source_peek_uid (source); + + foreach_data->list = g_slist_prepend ( + foreach_data->list, + g_strdup_printf ("%s\n%s", source_uid, string)); + } + + icalcomponent_free (vcal); +} + static void memo_shell_content_table_drag_data_get_cb (EMemoShellContent *memo_shell_content, gint row, @@ -99,7 +139,33 @@ memo_shell_content_table_drag_data_get_cb (EMemoShellContent *memo_shell_content guint info, guint time) { - /* FIXME */ + EMemoTable *memo_table; + ETable *table; + + struct { + ECalModel *model; + GSList *list; + } foreach_data; + + if (info != TARGET_VCALENDAR) + return; + + memo_table = e_memo_shell_content_get_memo_table (memo_shell_content); + table = e_memo_table_get_table (memo_table); + + foreach_data.model = e_memo_table_get_model (memo_table); + foreach_data.list = NULL; + + e_table_selected_row_foreach ( + table, memo_shell_content_table_foreach_cb, + &foreach_data); + + if (foreach_data.list != NULL) { + cal_comp_selection_set_string_list ( + selection_data, foreach_data.list); + g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL); + g_slist_free (foreach_data.list); + } } static void @@ -110,7 +176,7 @@ memo_shell_content_table_drag_data_delete_cb (EMemoShellContent *memo_shell_cont { /* Moved components are deleted from source immediately when moved, * because some of them can be part of destination source, and we - * don't want to delete not-moved tasks. There is no such information + * don't want to delete not-moved memos. There is no such information * which event has been moved and which not, so skip this method. */ } diff --git a/calendar/modules/e-memo-shell-sidebar.c b/calendar/modules/e-memo-shell-sidebar.c index d66f4881b1..d676a9bf58 100644 --- a/calendar/modules/e-memo-shell-sidebar.c +++ b/calendar/modules/e-memo-shell-sidebar.c @@ -29,7 +29,7 @@ #include "e-util/e-util.h" #include "calendar/common/authentication.h" #include "calendar/gui/calendar-config.h" -#include "calendar/gui/e-calendar-selector.h" +#include "calendar/gui/e-memo-list-selector.h" #include "calendar/gui/misc.h" #include "e-memo-shell-view.h" @@ -388,7 +388,7 @@ memo_shell_sidebar_constructed (GObject *object) container = GTK_CONTAINER (widget); - widget = e_calendar_selector_new (source_list); + widget = e_memo_list_selector_new (source_list); e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE); gtk_container_add (container, widget); a11y = gtk_widget_get_accessible (widget); diff --git a/calendar/modules/e-task-shell-content.c b/calendar/modules/e-task-shell-content.c index febd0c9ef2..5e98bf2f49 100644 --- a/calendar/modules/e-task-shell-content.c +++ b/calendar/modules/e-task-shell-content.c @@ -26,6 +26,7 @@ #include "e-util/gconf-bridge.h" #include "calendar/gui/calendar-config.h" +#include "calendar/gui/comp-util.h" #include "calendar/gui/e-cal-model-tasks.h" #include "calendar/gui/e-calendar-table.h" #include "calendar/gui/e-calendar-table-config.h" @@ -91,6 +92,45 @@ task_shell_content_display_view_cb (ETaskShellContent *task_shell_content, gal_view_etable_attach_table (GAL_VIEW_ETABLE (gal_view), table); } +static void +task_shell_content_table_foreach_cb (gint model_row, + gpointer user_data) +{ + ECalModelComponent *comp_data; + icalcomponent *clone; + icalcomponent *vcal; + gchar *string; + + struct { + ECalModel *model; + GSList *list; + } *foreach_data = user_data; + + comp_data = e_cal_model_get_component_at ( + foreach_data->model, model_row); + + vcal = e_cal_util_new_top_level (); + clone = icalcomponent_new_clone (comp_data->icalcomp); + e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp); + icalcomponent_add_component (vcal, clone); + + /* String is owned by libical; do not free. */ + string = icalcomponent_as_ical_string (vcal); + if (string != NULL) { + ESource *source; + const gchar *source_uid; + + source = e_cal_get_source (comp_data->client); + source_uid = e_source_peek_uid (source); + + foreach_data->list = g_slist_prepend ( + foreach_data->list, + g_strdup_printf ("%s\n%s", source_uid, string)); + } + + icalcomponent_free (vcal); +} + static void task_shell_content_table_drag_data_get_cb (ETaskShellContent *task_shell_content, gint row, @@ -100,7 +140,33 @@ task_shell_content_table_drag_data_get_cb (ETaskShellContent *task_shell_content guint info, guint time) { - /* FIXME */ + ECalendarTable *task_table; + ETable *table; + + struct { + ECalModel *model; + GSList *list; + } foreach_data; + + if (info != TARGET_VCALENDAR) + return; + + task_table = e_task_shell_content_get_task_table (task_shell_content); + table = e_calendar_table_get_table (task_table); + + foreach_data.model = e_calendar_table_get_model (task_table); + foreach_data.list = NULL; + + e_table_selected_row_foreach ( + table, task_shell_content_table_foreach_cb, + &foreach_data); + + if (foreach_data.list != NULL) { + cal_comp_selection_set_string_list ( + selection_data, foreach_data.list); + g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL); + g_slist_free (foreach_data.list); + } } static void diff --git a/calendar/modules/e-task-shell-sidebar.c b/calendar/modules/e-task-shell-sidebar.c index bce2684515..6f2f1bb409 100644 --- a/calendar/modules/e-task-shell-sidebar.c +++ b/calendar/modules/e-task-shell-sidebar.c @@ -29,7 +29,7 @@ #include "e-util/e-util.h" #include "calendar/common/authentication.h" #include "calendar/gui/calendar-config.h" -#include "calendar/gui/e-calendar-selector.h" +#include "calendar/gui/e-task-list-selector.h" #include "calendar/gui/misc.h" #include "e-task-shell-view.h" @@ -361,7 +361,7 @@ task_shell_sidebar_constructed (GObject *object) container = GTK_CONTAINER (widget); - widget = e_calendar_selector_new (source_list); + widget = e_task_list_selector_new (source_list); e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE); gtk_container_add (container, widget); a11y = gtk_widget_get_accessible (widget); -- cgit v1.2.3