aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook
diff options
context:
space:
mode:
authorHans Petter Jansson <hpj@ximian.com>2004-06-24 06:40:24 +0800
committerHans Petter <hansp@src.gnome.org>2004-06-24 06:40:24 +0800
commit54a5d78f7876c7ebbe6e973a7d0321efb48128e0 (patch)
treec4cf1430105eddc54c3ea70e5aee7648e1effac6 /addressbook
parent00fc3d7f480b020e90de31894f575c54dd78a034 (diff)
downloadgsoc2013-evolution-54a5d78f7876c7ebbe6e973a7d0321efb48128e0.tar.gz
gsoc2013-evolution-54a5d78f7876c7ebbe6e973a7d0321efb48128e0.tar.zst
gsoc2013-evolution-54a5d78f7876c7ebbe6e973a7d0321efb48128e0.zip
Add an x-source-vcard target entry that includes the source book URI.
2004-06-23 Hans Petter Jansson <hpj@ximian.com> * gui/component/addressbook-view.c: Add an x-source-vcard target entry that includes the source book URI. (destroy_merge_context): Implement. (removed_contact_cb): Implement. (merged_contact_cb): Implement. (selector_tree_drag_data_received): Get the source and target books, and see if we need to remove contacts from source after they're added to target. Copy contacts sequentially, not in parallel, with a callback. * gui/widgets/e-addressbook-view.c: Add an x-source-vcard target entry that includes the source book URI. (table_drag_data_delete): Remove. This is handled by the drag target. (table_drag_data_get): Handle more than one contact. Supply source. (create_table_view): Don't connect to the delete signal. * gui/widgets/e-minicard-view.c: Add an x-source-vcard target entry that includes the source book URI. (e_minicard_view_drag_data_delete): Remove. This is handled by the drag target. (e_minicard_view_drag_data_get): Handle x-source-vcard target. (e_minicard_view_drag_begin): Don't connect to the delete signal. (e_minicard_view_dispose): Don't disconnect from the delete signal. (e_minicard_view_init): Don't init delete_id. * gui/widgets/e-minicard-view.h: Remove delete_id from struct. * util/eab-book-util.[ch] (eab_contact_list_from_string): Skip the source URI if present. (eab_book_and_contact_list_from_string): Create the source book from the provided URI, if present. (eab_book_and_contact_list_to_string): Include the book URI in generated string. svn path=/trunk/; revision=26485
Diffstat (limited to 'addressbook')
-rw-r--r--addressbook/ChangeLog36
-rw-r--r--addressbook/gui/component/addressbook-view.c138
-rw-r--r--addressbook/gui/widgets/e-addressbook-view.c62
-rw-r--r--addressbook/gui/widgets/e-minicard-view.c50
-rw-r--r--addressbook/gui/widgets/e-minicard-view.h2
-rw-r--r--addressbook/util/eab-book-util.c65
-rw-r--r--addressbook/util/eab-book-util.h3
7 files changed, 257 insertions, 99 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index abfccf0a9f..9c48b34a98 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,39 @@
+2004-06-23 Hans Petter Jansson <hpj@ximian.com>
+
+ * gui/component/addressbook-view.c: Add an x-source-vcard target entry
+ that includes the source book URI.
+ (destroy_merge_context): Implement.
+ (removed_contact_cb): Implement.
+ (merged_contact_cb): Implement.
+ (selector_tree_drag_data_received): Get the source and target books,
+ and see if we need to remove contacts from source after they're added
+ to target. Copy contacts sequentially, not in parallel, with a
+ callback.
+
+ * gui/widgets/e-addressbook-view.c: Add an x-source-vcard target entry
+ that includes the source book URI.
+ (table_drag_data_delete): Remove. This is handled by the drag target.
+ (table_drag_data_get): Handle more than one contact. Supply source.
+ (create_table_view): Don't connect to the delete signal.
+
+ * gui/widgets/e-minicard-view.c: Add an x-source-vcard target entry
+ that includes the source book URI.
+ (e_minicard_view_drag_data_delete): Remove. This is handled by the
+ drag target.
+ (e_minicard_view_drag_data_get): Handle x-source-vcard target.
+ (e_minicard_view_drag_begin): Don't connect to the delete signal.
+ (e_minicard_view_dispose): Don't disconnect from the delete signal.
+ (e_minicard_view_init): Don't init delete_id.
+
+ * gui/widgets/e-minicard-view.h: Remove delete_id from struct.
+
+ * util/eab-book-util.[ch] (eab_contact_list_from_string): Skip the
+ source URI if present.
+ (eab_book_and_contact_list_from_string): Create the source book from
+ the provided URI, if present.
+ (eab_book_and_contact_list_to_string): Include the book URI in
+ generated string.
+
2004-06-23 Rodney Dawes <dobey@novell.com>
* gui/component/select-names/select-names.glade:
diff --git a/addressbook/gui/component/addressbook-view.c b/addressbook/gui/component/addressbook-view.c
index 149bf3521b..cfedd0b949 100644
--- a/addressbook/gui/component/addressbook-view.c
+++ b/addressbook/gui/component/addressbook-view.c
@@ -93,9 +93,12 @@ struct _AddressbookViewPrivate {
enum DndTargetType {
DND_TARGET_TYPE_VCARD_LIST,
+ DND_TARGET_TYPE_SOURCE_VCARD_LIST
};
-#define VCARD_TYPE "text/x-vcard"
+#define VCARD_TYPE "text/x-vcard"
+#define SOURCE_VCARD_TYPE "text/x-source-vcard"
static GtkTargetEntry drag_types[] = {
+ { SOURCE_VCARD_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD_LIST },
{ VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD_LIST }
};
static gint num_drag_types = sizeof(drag_types) / sizeof(drag_types[0]);
@@ -791,6 +794,79 @@ selector_tree_drag_motion (GtkWidget *widget,
return TRUE;
}
+typedef struct
+{
+ guint remove_from_source : 1;
+ guint copy_done : 1;
+ gint pending_removals;
+
+ EContact *current_contact;
+ GList *remaining_contacts;
+
+ EBook *source_book;
+ EBook *target_book;
+}
+MergeContext;
+
+static void
+destroy_merge_context (MergeContext *merge_context)
+{
+ if (merge_context->source_book)
+ g_object_unref (merge_context->source_book);
+ if (merge_context->target_book)
+ g_object_unref (merge_context->target_book);
+
+ g_free (merge_context);
+}
+
+static void
+removed_contact_cb (EBook *book, EBookStatus status, gpointer closure)
+{
+ MergeContext *merge_context = closure;
+
+ merge_context->pending_removals--;
+
+ if (merge_context->copy_done && merge_context->pending_removals == 0) {
+ /* Finished */
+
+ destroy_merge_context (merge_context);
+ }
+}
+
+static void
+merged_contact_cb (EBook *book, EBookStatus status, const char *id, gpointer closure)
+{
+ MergeContext *merge_context = closure;
+
+ if (merge_context->remove_from_source && status == E_BOOK_ERROR_OK) {
+ /* Remove previous contact from source */
+
+ e_book_async_remove_contact (merge_context->source_book, merge_context->current_contact,
+ removed_contact_cb, merge_context);
+ merge_context->pending_removals++;
+ }
+
+ g_object_unref (merge_context->current_contact);
+
+ if (merge_context->remaining_contacts) {
+ /* Copy next contact */
+
+ merge_context->current_contact = merge_context->remaining_contacts->data;
+ merge_context->remaining_contacts = g_list_delete_link (merge_context->remaining_contacts,
+ merge_context->remaining_contacts);
+ eab_merging_book_add_contact (merge_context->target_book, merge_context->current_contact,
+ merged_contact_cb, merge_context);
+ } else if (merge_context->pending_removals == 0) {
+ /* Finished */
+
+ destroy_merge_context (merge_context);
+ } else {
+ /* Finished, but have pending removals */
+
+ merge_context->copy_done = TRUE;
+ }
+}
+
static gboolean
selector_tree_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
@@ -803,12 +879,13 @@ selector_tree_drag_data_received (GtkWidget *widget,
{
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
- gpointer source = NULL;
+ gpointer source, target = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean success = FALSE;
- EBook *book;
+ EBook *source_book, *target_book;
+ MergeContext *merge_context;
GList *contactlist;
GList *l;
@@ -821,37 +898,52 @@ selector_tree_drag_data_received (GtkWidget *widget,
if (!gtk_tree_model_get_iter (model, &iter, path))
goto finish;
- gtk_tree_model_get (model, &iter, 0, &source, -1);
+ gtk_tree_model_get (model, &iter, 0, &target, -1);
- if (E_IS_SOURCE_GROUP (source) || e_source_get_readonly (source))
+ if (E_IS_SOURCE_GROUP (target) || e_source_get_readonly (target))
goto finish;
- book = e_book_new (source, NULL);
- if (!book) {
+ target_book = e_book_new (target, NULL);
+ if (!target_book) {
g_message (G_STRLOC ":Couldn't create EBook.");
return FALSE;
}
- e_book_open (book, TRUE, NULL);
- contactlist = eab_contact_list_from_string (data->data);
-
- for (l = contactlist; l; l = l->next) {
- EContact *contact = l->data;
-
- /* XXX NULL for a callback /sigh */
- if (contact)
- eab_merging_book_add_contact (book, contact, NULL /* XXX */, NULL);
- success = TRUE;
+ e_book_open (target_book, TRUE, NULL);
+
+ eab_book_and_contact_list_from_string (data->data, &source_book, &contactlist);
+
+ if (source_book) {
+ if (!e_book_open (source_book, FALSE, NULL)) {
+ g_warning (G_STRLOC ": Couldn't open source EBook.");
+ g_object_unref (source_book);
+ source_book = NULL;
+ }
+ } else {
+ g_warning (G_STRLOC ": No source EBook provided.");
}
-
- g_list_foreach (contactlist, (GFunc)g_object_unref, NULL);
- g_list_free (contactlist);
- g_object_unref (book);
+
+ /* Set up merge context */
+
+ merge_context = g_new0 (MergeContext, 1);
+
+ merge_context->source_book = source_book;
+ merge_context->target_book = target_book;
+
+ merge_context->current_contact = contactlist->data;
+ merge_context->remaining_contacts = g_list_delete_link (contactlist, contactlist);
+
+ merge_context->remove_from_source = context->suggested_action == GDK_ACTION_MOVE ? TRUE : FALSE;
+
+ /* Start merge */
+
+ eab_merging_book_add_contact (target_book, merge_context->current_contact,
+ merged_contact_cb, merge_context);
finish:
if (path)
gtk_tree_path_free (path);
- if (source)
- g_object_unref (source);
+ if (target)
+ g_object_unref (target);
gtk_drag_finish (context, success, context->action == GDK_ACTION_MOVE, time);
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c
index 44db0a1edd..907309348a 100644
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@ -98,6 +98,7 @@ static void writable_status (GtkObject *object, gboolean writable, EABView *e
static void backend_died (GtkObject *object, EABView *eav);
static void contact_changed (EABModel *model, gint index, EABView *eav);
static void contact_removed (EABModel *model, gint index, EABView *eav);
+static GList *get_selected_contacts (EABView *view);
static void command_state_change (EABView *eav);
@@ -137,11 +138,14 @@ enum {
};
enum DndTargetType {
- DND_TARGET_TYPE_VCARD,
+ DND_TARGET_TYPE_SOURCE_VCARD,
+ DND_TARGET_TYPE_VCARD
};
#define VCARD_TYPE "text/x-vcard"
+#define SOURCE_VCARD_TYPE "text/x-source-vcard"
static GtkTargetEntry drag_types[] = {
- { VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD },
+ { SOURCE_VCARD_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD },
+ { VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD }
};
static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);
@@ -1218,36 +1222,6 @@ table_white_space_event(ETableScrolled *table, GdkEvent *event, EABView *view)
}
static void
-table_drag_data_delete (ETable *table,
- int row,
- int col,
- GdkDragContext *context,
- gpointer user_data)
-{
- EABView *view = user_data;
- EContact *contact;
- EBook *book;
-
- if (!E_IS_ADDRESSBOOK_TABLE_ADAPTER(view->object))
- return;
-
- g_object_get(view->model,
- "book", &book,
- NULL);
-
- contact = eab_model_contact_at(view->model, row);
- /* Remove the card. */
- /* XXX no callback specified... ugh */
- e_book_async_remove_contact (book,
- contact,
- NULL,
- NULL);
-
- g_object_unref(book);
-}
-
-
-static void
table_drag_data_get (ETable *table,
int row,
int col,
@@ -1258,15 +1232,18 @@ table_drag_data_get (ETable *table,
gpointer user_data)
{
EABView *view = user_data;
+ GList *contact_list;
if (!E_IS_ADDRESSBOOK_TABLE_ADAPTER(view->object))
return;
+ contact_list = get_selected_contacts (view);
+
switch (info) {
case DND_TARGET_TYPE_VCARD: {
char *value;
- value = e_vcard_to_string (E_VCARD (view->model->data[row]), EVC_FORMAT_VCARD_30);
+ value = eab_contact_list_to_string (contact_list);
gtk_selection_data_set (selection_data,
selection_data->target,
@@ -1274,7 +1251,21 @@ table_drag_data_get (ETable *table,
value, strlen (value));
break;
}
+ case DND_TARGET_TYPE_SOURCE_VCARD: {
+ char *value;
+
+ value = eab_book_and_contact_list_to_string (view->book, contact_list);
+
+ gtk_selection_data_set (selection_data,
+ selection_data->target,
+ 8,
+ value, strlen (value));
+ break;
}
+ }
+
+ g_list_foreach (contact_list, (GFunc) g_object_unref, NULL);
+ g_list_free (contact_list);
}
static void
@@ -1433,11 +1424,6 @@ create_table_view (EABView *view)
"table_drag_data_get",
G_CALLBACK (table_drag_data_get),
view);
-
- g_signal_connect (E_TABLE_SCROLLED(table)->table,
- "table_drag_data_delete",
- G_CALLBACK (table_drag_data_delete),
- view);
gtk_paned_add1 (GTK_PANED (view->paned), table);
diff --git a/addressbook/gui/widgets/e-minicard-view.c b/addressbook/gui/widgets/e-minicard-view.c
index 60893d45f1..6cae674c98 100644
--- a/addressbook/gui/widgets/e-minicard-view.c
+++ b/addressbook/gui/widgets/e-minicard-view.c
@@ -62,9 +62,12 @@ static guint signals [LAST_SIGNAL] = {0, };
enum DndTargetType {
DND_TARGET_TYPE_VCARD_LIST,
+ DND_TARGET_TYPE_SOURCE_VCARD_LIST
};
#define VCARD_LIST_TYPE "text/x-vcard"
+#define SOURCE_VCARD_LIST_TYPE "text/x-source-vcard"
static GtkTargetEntry drag_types[] = {
+ { SOURCE_VCARD_LIST_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD_LIST },
{ VCARD_LIST_TYPE, 0, DND_TARGET_TYPE_VCARD_LIST }
};
static gint num_drag_types = sizeof(drag_types) / sizeof(drag_types[0]);
@@ -92,32 +95,19 @@ e_minicard_view_drag_data_get(GtkWidget *widget,
value, strlen (value));
break;
}
- }
-}
-
-static void
-e_minicard_view_drag_data_delete (GtkWidget *widget,
- GdkDragContext *context,
- EMinicardView *view)
-{
- EBook *book;
- GList *l;
-
- if (!E_IS_MINICARD_VIEW (view))
- return;
+ case DND_TARGET_TYPE_SOURCE_VCARD_LIST: {
+ EBook *book;
+ char *value;
+
+ g_object_get (view->adapter, "book", &book, NULL);
+ value = eab_book_and_contact_list_to_string (book, view->drag_list);
- if (!view->drag_list) {
- g_warning ("e_minicard_view_drag_data_delete called without contact list");
- return;
+ gtk_selection_data_set (selection_data,
+ selection_data->target,
+ 8,
+ value, strlen (value));
+ break;
}
-
- g_object_get (view->adapter, "book", &book, NULL);
-
- for (l = view->drag_list; l; l = g_list_next (l)) {
- EContact *contact = l->data;
-
- /* XXX no callback */
- e_book_async_remove_contact (book, contact, NULL, NULL);
}
}
@@ -152,11 +142,6 @@ e_minicard_view_drag_begin (EAddressbookReflowAdapter *adapter, GdkEvent *event,
"drag_data_get",
G_CALLBACK (e_minicard_view_drag_data_get),
view);
- if (!view->canvas_drag_data_delete_id)
- view->canvas_drag_data_delete_id = g_signal_connect (GNOME_CANVAS_ITEM (view)->canvas,
- "drag_data_delete",
- G_CALLBACK (e_minicard_view_drag_data_delete),
- view);
gtk_drag_set_icon_default (context);
@@ -314,12 +299,6 @@ e_minicard_view_dispose (GObject *object)
view->canvas_drag_data_get_id = 0;
}
- if (view->canvas_drag_data_delete_id) {
- g_signal_handler_disconnect (GNOME_CANVAS_ITEM (view)->canvas,
- view->canvas_drag_data_delete_id);
- view->canvas_drag_data_delete_id = 0;
- }
-
if (view->adapter) {
if (view->writable_status_id) {
EABModel *model;
@@ -545,7 +524,6 @@ e_minicard_view_init (EMinicardView *view)
view->drag_list = NULL;
view->adapter = NULL;
view->canvas_drag_data_get_id = 0;
- view->canvas_drag_data_delete_id = 0;
view->writable_status_id = 0;
set_empty_message (view);
diff --git a/addressbook/gui/widgets/e-minicard-view.h b/addressbook/gui/widgets/e-minicard-view.h
index 679e5252c0..50964568cf 100644
--- a/addressbook/gui/widgets/e-minicard-view.h
+++ b/addressbook/gui/widgets/e-minicard-view.h
@@ -69,8 +69,6 @@ struct _EMinicardView
GList *drag_list;
guint canvas_drag_data_get_id;
- guint canvas_drag_data_delete_id;
-
guint writable_status_id;
};
diff --git a/addressbook/util/eab-book-util.c b/addressbook/util/eab-book-util.c
index 53a09c323b..f6429dee0a 100644
--- a/addressbook/util/eab-book-util.c
+++ b/addressbook/util/eab-book-util.c
@@ -188,6 +188,18 @@ eab_contact_list_from_string (const char *str)
char *q;
char *blank_line;
+ if (!p)
+ return NULL;
+
+ if (!strncmp (p, "Book: ", 6)) {
+ p = strchr (p, '\n');
+ if (!p) {
+ g_warning (G_STRLOC ": Got book but no newline!");
+ return NULL;
+ }
+ p++;
+ }
+
while (*p) {
if (*p != '\r') g_string_append_c (gstr, *p);
@@ -240,6 +252,59 @@ eab_contact_list_to_string (GList *contacts)
return g_string_free (str, FALSE);
}
+gboolean
+eab_book_and_contact_list_from_string (const char *str, EBook **book, GList **contacts)
+{
+ const char *s0, *s1;
+ char *uri;
+
+ g_return_val_if_fail (str != NULL, FALSE);
+ g_return_val_if_fail (book != NULL, FALSE);
+ g_return_val_if_fail (contacts != NULL, FALSE);
+
+ *contacts = eab_contact_list_from_string (str);
+
+ if (!strncmp (str, "Book: ", 6)) {
+ s0 = str + 6;
+ s1 = strchr (str, '\r');
+
+ if (!s1)
+ s1 = strchr (str, '\n');
+ } else {
+ s0 = NULL;
+ s1 = NULL;
+ }
+
+ if (!s0 || !s1) {
+ *book = NULL;
+ return FALSE;
+ }
+
+ uri = g_strndup (s0, s1 - s0);
+ *book = e_book_new_from_uri (uri, NULL);
+ g_free (uri);
+
+ return *book ? TRUE : FALSE;
+}
+
+char *
+eab_book_and_contact_list_to_string (EBook *book, GList *contacts)
+{
+ char *s0, *s1;
+
+ s0 = eab_contact_list_to_string (contacts);
+ if (!s0)
+ s0 = g_strdup ("");
+
+ if (book)
+ s1 = g_strconcat ("Book: ", e_book_get_uri (book), "\r\n", s0, NULL);
+ else
+ s1 = g_strdup (s0);
+
+ g_free (s0);
+ return s1;
+}
+
#if notyet
/*
* Convenience routine to check for addresses in the local address book.
diff --git a/addressbook/util/eab-book-util.h b/addressbook/util/eab-book-util.h
index ae3a45ef35..c1362f1571 100644
--- a/addressbook/util/eab-book-util.h
+++ b/addressbook/util/eab-book-util.h
@@ -54,6 +54,9 @@ guint eab_nickname_query (EBook *
GList *eab_contact_list_from_string (const char *str);
char *eab_contact_list_to_string (GList *contacts);
+gboolean eab_book_and_contact_list_from_string (const char *str, EBook **book, GList **contacts);
+char *eab_book_and_contact_list_to_string (EBook *book, GList *contacts);
+
/* Returns the EContact associated to email in the callback,
or NULL if no match is found in the default address book. */
void eab_query_address_default (const gchar *email,