[Commits] [SCM] claws branch, master, updated. 3.16.0-107-gf25722a

wwp at claws-mail.org wwp at claws-mail.org
Tue Apr 10 00:25:32 CEST 2018


The branch, master has been updated
       via  f25722af77b9378ce0fcfb4c3d09b9bd3c01902a (commit)
      from  a5b4afcf66c7f86f4d3b6ce9a5a792ea124541fd (commit)

Summary of changes:
 src/Makefile.am   |    2 +
 src/addressbook.c |   58 ++++++-
 src/addressbook.h |    5 +
 src/addrmerge.c   |  496 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 555 insertions(+), 6 deletions(-)
 create mode 100644 src/addrmerge.c


- Log -----------------------------------------------------------------
commit f25722af77b9378ce0fcfb4c3d09b9bd3c01902a
Author: wwp <wwp at free.fr>
Date:   Tue Apr 10 00:23:14 2018 +0200

    Add a basic contact merging feature to the address book, thanks to
    Charles Lehner <cel at celehner.com>.
    Closes bug 3346: Contact merging

diff --git a/src/Makefile.am b/src/Makefile.am
index d4eafbc..460c182 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,6 +45,7 @@ orig_abook_source = \
 	addrquery.c \
 	addrselect.c \
 	addrduplicates.c \
+	addrmerge.c \
 	browseldap.c \
 	editaddress.c \
 	editaddress_other_attributes_ldap.c \
@@ -93,6 +94,7 @@ abook_headers = \
 	addrquery.h \
 	addrselect.h \
 	addrduplicates.h \
+	addrmerge.h \
 	browseldap.h \
 	editaddress.h \
 	editaddress_other_attributes_ldap.h \
diff --git a/src/addressbook.c b/src/addressbook.c
index 77c3b65..30adcce 100644
--- a/src/addressbook.c
+++ b/src/addressbook.c
@@ -57,6 +57,7 @@
 #include "addrcache.h"
 #include "addrbook.h"
 #include "addrindex.h"
+#include "addrmerge.h"
 #include "addressadd.h"
 #include "addrduplicates.h"
 #include "addressbook_foldersel.h"
@@ -306,10 +307,6 @@ static void addressbook_folder_load_one_person	(GtkCMCTree *clist,
 						 ItemPerson *person,  
 						 AddressTypeControlItem *atci, 
 						 AddressTypeControlItem *atciMail);
-static void addressbook_folder_refresh_one_person(GtkCMCTree *clist, 
-						  ItemPerson *person);
-static void addressbook_folder_remove_one_person(GtkCMCTree *clist, 
-						 ItemPerson *person);
 static void addressbook_folder_remove_node	(GtkCMCTree *clist, 
 						 GtkCMCTreeNode *node);
 
@@ -352,6 +349,7 @@ static void addressbook_treenode_copy_cb	( GtkAction *action, gpointer data );
 static void addressbook_treenode_paste_cb	( GtkAction *action, gpointer data );
 
 static void addressbook_mail_to_cb		( GtkAction *action, gpointer data );
+static void addressbook_merge_cb		( GtkAction *action, gpointer data );
 
 #ifdef USE_LDAP
 static void addressbook_browse_entry_cb		( GtkAction *action, gpointer data );
@@ -442,6 +440,7 @@ static GtkActionEntry addressbook_entries[] =
 	{"Address/NewGroup",		NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
 	/* {"Address/---",			NULL, "---", NULL, NULL, NULL }, */
 	{"Address/Mailto",		NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
+	{"Address/Merge",		NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
 
 
 /* Tools menu */
@@ -494,6 +493,7 @@ static GtkActionEntry addressbook_list_popup_entries[] =
 #ifdef USE_LDAP
 	{"ABListPopup/BrowseEntry",	NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
 #endif
+	{"ABListPopup/Merge",		NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
 };
 
 /**
@@ -978,6 +978,7 @@ static void addressbook_create(void)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
 
 /* Tools menu */
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
@@ -1281,6 +1282,7 @@ static void addressbook_create(void)
 #ifdef USE_LDAP
 	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
 #endif
+	MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
 	list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
 				gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
 
@@ -1797,6 +1799,7 @@ static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup",   sensitive );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto",     sensitive );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge",      sensitive );
 	gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
 	gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
 }
@@ -1985,12 +1988,16 @@ static void addressbook_list_menu_setup( void ) {
 	AdapterDSource *ads = NULL;
 	AddressInterface *iface = NULL;
 	AddressDataSource *ds = NULL;
+	GList *list;
+	AddrItemObject *aio;
+	AddrSelectItem *item;
 	gboolean canEdit = FALSE;
 	gboolean canDelete = FALSE;
 	gboolean canCut = FALSE;
 	gboolean canCopy = FALSE;
 	gboolean canPaste = FALSE;
 	gboolean canBrowse = FALSE;
+	gboolean canMerge = FALSE;
 
 	pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
 	if( pobj == NULL ) return;
@@ -2068,11 +2075,23 @@ static void addressbook_list_menu_setup( void ) {
 		canBrowse = FALSE;
 	}
 
+	/* Allow merging persons or emails are selected */
+	list = _addressSelect_->listSelect;
+	if (list && list->next ) {
+		item = list->data;
+		aio = ( AddrItemObject * ) item->addressItem;
+		if( aio->type == ITEMTYPE_EMAIL ||
+				aio->type == ITEMTYPE_PERSON ) {
+			canMerge = TRUE;
+		}
+	}
+
 	/* Forbid write changes when read-only */
 	if( iface && iface->readOnly ) {
 		canCut = FALSE;
 		canDelete = FALSE;
 		canPaste = FALSE;
+		canMerge = FALSE;
 	}
 
 	/* Now go finalize menu items */
@@ -2084,6 +2103,7 @@ static void addressbook_list_menu_setup( void ) {
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste",         canPaste );
 
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto",       canCopy );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge",        canMerge );
 
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut",           canCut );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy",          canCopy );
@@ -2092,6 +2112,7 @@ static void addressbook_list_menu_setup( void ) {
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit",    canEdit );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete",  canDelete );
 	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
+	cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge",  canMerge );
 
 	gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
 	gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
@@ -2371,6 +2392,31 @@ static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
 	}
 }
 
+static void addressbook_merge_list( AddrSelectList *list ) {
+	GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
+	GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
+	AddressObject *pobj;
+	AddressDataSource *ds = NULL;
+
+	pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
+	cm_return_if_fail(pobj != NULL);
+
+	ds = addressbook_find_datasource( addrbook.treeSelected );
+	if( ds == NULL ) return;
+
+	addrmerge_merge(clist, pobj, ds, list);
+}
+
+/**
+ * Merge selected entries in the address list
+ */
+static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
+	if( addrselect_test_empty( _addressSelect_ ) )
+		return;
+
+	addressbook_merge_list( _addressSelect_ );
+}
+
 static void addressbook_list_row_selected( GtkCMCTree *clist,
 					   GtkCMCTreeNode *node,
 					   gint column,
@@ -3739,7 +3785,7 @@ static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *n
 		addrbook.treeSelected );
 }
 
-static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
+void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
 	AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
 	AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
 	GtkCMCTreeNode *node;
@@ -3761,7 +3807,7 @@ static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson
 	}
 }
 
-static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
+void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
 	GtkCMCTreeNode *node;
 	
 	if( person == NULL ) return;
diff --git a/src/addressbook.h b/src/addressbook.h
index ce5c707..beb92cd 100644
--- a/src/addressbook.h
+++ b/src/addressbook.h
@@ -60,5 +60,10 @@ void addressbook_refresh( void );
 gchar *addressbook_set_col_name_guard(gchar *value);
 void addressbook_reflect_prefs_pixmap_theme(void);
 
+void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
+						  ItemPerson *person);
+void addressbook_folder_remove_one_person(GtkCMCTree *clist,
+						 ItemPerson *person);
+
 #endif /* __ADDRESSBOOK_H__ */
 
diff --git a/src/addrmerge.c b/src/addrmerge.c
new file mode 100644
index 0000000..363bab7
--- /dev/null
+++ b/src/addrmerge.c
@@ -0,0 +1,496 @@
+/* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2014 Charles Lehner and the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+#include "defs.h"
+
+#ifdef USE_LDAP
+#include "ldapserver.h"
+#include "ldapupdate.h"
+#endif
+#include "addrbook.h"
+#include "addressbook.h"
+#include "addressitem.h"
+#include "addrmerge.h"
+#include "alertpanel.h"
+#include "gtkutils.h"
+#include "utils.h"
+#include "prefs_common.h"
+
+enum
+{
+	COL_DISPLAYNAME,
+	COL_FIRSTNAME,
+	COL_LASTNAME,
+	COL_NICKNAME,
+	N_NAME_COLS
+};
+
+enum
+{
+	SET_ICON,
+	SET_PERSON,
+	N_SET_COLUMNS
+};
+
+static void addrmerge_done(struct AddrMergePage *page)
+{
+	g_list_free(page->emails);
+	g_list_free(page->persons);
+	gtk_widget_destroy(GTK_WIDGET(page->dialog));
+	g_free(page);
+}
+
+static void addrmerge_do_merge(struct AddrMergePage *page)
+{
+	GList *node;
+	ItemEMail *email;
+	ItemPerson *person;
+	ItemPerson *target = page->target;
+	ItemPerson *nameTarget = page->nameTarget;
+
+	gtk_cmclist_freeze(GTK_CMCLIST(page->clist));
+
+	/* Update target name */
+	if (nameTarget && nameTarget != target) {
+		target->status = UPDATE_ENTRY;
+		addritem_person_set_first_name( target, nameTarget->firstName );
+		addritem_person_set_last_name( target, nameTarget->lastName );
+		addritem_person_set_nick_name( target, nameTarget->nickName );
+		addritem_person_set_common_name( target, ADDRITEM_NAME(nameTarget ));
+	}
+
+	/* Merge emails into target */
+	for (node = page->emails; node; node = node->next) {
+		email = node->data;
+		person = ( ItemPerson * ) ADDRITEM_PARENT(email);
+		/* Remove the email from the person */
+		email = addrbook_person_remove_email( page->abf, person, email );
+		if( email ) {
+			addrcache_remove_email( page->abf->addressCache, email );
+			/* Add the email to the target */
+			addrcache_person_add_email( page->abf->addressCache, target, email );
+		}
+		person->status = UPDATE_ENTRY;
+		addressbook_folder_refresh_one_person( page->clist, person );
+	}
+
+	/* Merge persons into target */
+	for (node = page->persons; node; node = node->next) {
+		GList *nodeE, *nodeA;
+		person = node->data;
+
+		if (person == target) continue;
+		person->status = DELETE_ENTRY;
+
+		/* Move all emails to the target */
+		for (nodeE = person->listEMail; nodeE; nodeE = nodeE->next) {
+			email = nodeE->data;
+			addritem_person_add_email( target, email );
+		}
+		g_list_free( person->listEMail );
+		person->listEMail = NULL;
+
+		/* Move all attributes to the target */
+		for (nodeA = person->listAttrib; nodeA; nodeA = nodeA->next) {
+			UserAttribute *attrib = nodeA->data;
+			addritem_person_add_attribute( target, attrib );
+		}
+		g_list_free( person->listAttrib );
+		person->listAttrib = NULL;
+
+		/* Remove the person */
+		addrselect_list_remove( page->addressSelect, (AddrItemObject *)person );
+		addressbook_folder_remove_one_person( page->clist, person );
+		if (page->pobj->type == ADDR_ITEM_FOLDER)
+			addritem_folder_remove_person(ADAPTER_FOLDER(page->pobj)->itemFolder, person);
+		person = addrbook_remove_person( page->abf, person );
+
+		if( person ) {
+			gchar *filename = addritem_person_get_picture(person);
+			if ((strcmp2(person->picture, target->picture) &&
+					filename && is_file_exist(filename)))
+				claws_unlink(filename);
+			if (filename)
+				g_free(filename);
+			addritem_free_item_person( person );
+		}
+	}
+
+	addressbook_folder_refresh_one_person( page->clist, target );
+
+	addrbook_set_dirty( page->abf, TRUE );
+	addressbook_export_to_file();
+
+#ifdef USE_LDAP
+	if (page->ds && page->ds->type == ADDR_IF_LDAP) {
+		LdapServer *server = page->ds->rawDataSource;
+		ldapsvr_set_modified(server, TRUE);
+		ldapsvr_update_book(server, NULL);
+	}
+#endif
+	gtk_cmclist_thaw(GTK_CMCLIST(page->clist));
+
+	addrmerge_done(page);
+}
+
+static void addrmerge_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
+	struct AddrMergePage* page = data;
+
+	if (action != GTK_RESPONSE_ACCEPT)
+		return addrmerge_done(page);
+
+	addrmerge_do_merge(page);
+}
+
+static void addrmerge_update_dialog_sensitive( struct AddrMergePage *page )
+{
+	gboolean canMerge = (page->target && page->nameTarget);
+	gtk_dialog_set_response_sensitive( GTK_DIALOG(page->dialog),
+			GTK_RESPONSE_ACCEPT, canMerge );
+}
+
+static void addrmerge_name_selected( GtkCMCList *clist, gint row, gint column, GdkEvent *event, struct AddrMergePage *page )
+{
+	ItemPerson *person = gtk_cmclist_get_row_data( clist, row );
+	page->nameTarget = person;
+	addrmerge_update_dialog_sensitive(page);
+}
+
+static void addrmerge_picture_selected(GtkTreeView *treeview,
+		struct AddrMergePage *page)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GList *list;
+	ItemPerson *pictureTarget;
+
+	/* Get selected picture target */ 
+	model = gtk_icon_view_get_model(GTK_ICON_VIEW(page->iconView));
+	list = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(page->iconView));
+	page->target = NULL;
+	if (list != NULL) {
+		if (gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)list->data)) {
+			gtk_tree_model_get(model, &iter,
+					SET_PERSON, &pictureTarget,
+					-1);
+			page->target = pictureTarget;
+		}
+
+		gtk_tree_path_free(list->data);
+		g_list_free(list);
+	}
+	addrmerge_update_dialog_sensitive(page);
+}
+
+static void addrmerge_prompt( struct AddrMergePage *page )
+{
+	GtkWidget *dialog;
+	GtkWidget *frame;
+	GtkWidget *mvbox, *vbox, *hbox;
+	GtkWidget *label;
+	GtkWidget *iconView = NULL;
+	GtkWidget *namesList = NULL;
+	MainWindow *mainwin = mainwindow_get_mainwindow();
+	GtkListStore *store = NULL;
+	GtkTreeIter iter;
+	GList *node;
+	ItemPerson *person;
+	GError *error = NULL;
+	gchar *msg, *label_msg;
+
+	dialog = page->dialog = gtk_dialog_new_with_buttons (
+			_("Merge addresses"),
+			GTK_WINDOW(mainwin->window),
+			GTK_DIALOG_DESTROY_WITH_PARENT,
+			GTK_STOCK_CANCEL,
+			GTK_RESPONSE_CANCEL,
+			"_Merge",
+			GTK_RESPONSE_ACCEPT,
+			NULL);
+
+	g_signal_connect ( dialog, "response",
+			G_CALLBACK(addrmerge_dialog_cb), page);
+
+	mvbox = gtk_vbox_new(FALSE, 4);
+	gtk_container_add(GTK_CONTAINER(
+			gtk_dialog_get_content_area(GTK_DIALOG(dialog))), mvbox);
+	gtk_container_set_border_width(GTK_CONTAINER(mvbox), 8);
+	hbox = gtk_hbox_new(FALSE, 4);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
+	gtk_box_pack_start(GTK_BOX(mvbox),
+			hbox, FALSE, FALSE, 0);
+
+	msg = page->pickPicture || page->pickName ?
+		_("Merging %u contacts." ) :
+		_("Really merge these %u contacts?" );
+	label_msg = g_strdup_printf(msg,
+			g_list_length(page->addressSelect->listSelect));
+	label = gtk_label_new( label_msg );
+	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	g_free(label_msg);
+
+	if (page->pickPicture) {
+		GtkWidget *scrollwinPictures;
+
+		store = gtk_list_store_new(N_SET_COLUMNS,
+					GDK_TYPE_PIXBUF,
+					G_TYPE_POINTER,
+					-1);
+		gtk_list_store_clear(store);
+
+		vbox = gtkut_get_options_frame(mvbox, &frame,
+				_("Keep which picture?"));
+		gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
+
+		scrollwinPictures = gtk_scrolled_window_new(NULL, NULL);
+		gtk_container_set_border_width(GTK_CONTAINER(scrollwinPictures), 1);
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwinPictures),
+				GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwinPictures),
+				GTK_SHADOW_IN);
+		gtk_box_pack_start (GTK_BOX (vbox), scrollwinPictures, FALSE, FALSE, 0);
+		gtk_widget_set_size_request(scrollwinPictures, 464, 192);
+
+		iconView = gtk_icon_view_new_with_model(GTK_TREE_MODEL(store));
+		gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(iconView), GTK_SELECTION_SINGLE);
+		gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(iconView), SET_ICON);
+		gtk_container_add(GTK_CONTAINER(scrollwinPictures), GTK_WIDGET(iconView));
+		g_signal_connect(G_OBJECT(iconView), "selection-changed",
+				G_CALLBACK(addrmerge_picture_selected), page);
+
+		/* Add pictures from persons */
+		for (node = page->persons; node; node = node->next) {
+			gchar *filename;
+			person = node->data;
+			filename = addritem_person_get_picture(person);
+			if (filename && is_file_exist(filename)) {
+				GdkPixbuf *pixbuf;
+				GtkWidget *image;
+
+				pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+				if (error) {
+					debug_print("Failed to read image: \n%s",
+							error->message);
+					g_error_free(error);
+					continue;
+				}
+
+				image = gtk_image_new();
+				gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
+
+				gtk_list_store_append(store, &iter);
+				gtk_list_store_set(store, &iter,
+						SET_ICON, pixbuf,
+						SET_PERSON, person,
+						-1);
+			}
+			if (filename)
+				g_free(filename);
+		}
+	}
+
+	if (page->pickName) {
+		GtkWidget *scrollwinNames;
+		gchar *name_titles[N_NAME_COLS];
+
+		name_titles[COL_DISPLAYNAME] = _("Display Name");
+		name_titles[COL_FIRSTNAME] = _("First Name");
+		name_titles[COL_LASTNAME] = _("Last Name");
+		name_titles[COL_NICKNAME] = _("Nickname");
+
+		store = gtk_list_store_new(N_SET_COLUMNS,
+					GDK_TYPE_PIXBUF,
+					G_TYPE_POINTER,
+					-1);
+		gtk_list_store_clear(store);
+
+		vbox = gtkut_get_options_frame(mvbox, &frame,
+				_("Keep which name?"));
+		gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
+
+		scrollwinNames = gtk_scrolled_window_new(NULL, NULL);
+		gtk_container_set_border_width(GTK_CONTAINER(scrollwinNames), 1);
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwinNames),
+				GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwinNames),
+				GTK_SHADOW_IN);
+		gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scrollwinNames), FALSE, FALSE, 0);
+
+		namesList = gtk_cmclist_new_with_titles(N_NAME_COLS, name_titles);
+		gtk_widget_set_can_focus(GTK_CMCLIST(namesList)->column[0].button, FALSE);
+		gtk_cmclist_set_selection_mode(GTK_CMCLIST(namesList), GTK_SELECTION_BROWSE);
+		gtk_cmclist_set_column_width(GTK_CMCLIST(namesList), COL_DISPLAYNAME, 164);
+
+		gtk_container_add(GTK_CONTAINER(scrollwinNames), namesList);
+
+		/* Add names from persons */
+		for (node = page->persons; node; node = node->next) {
+			int row;
+			person = node->data;
+			gchar *text[N_NAME_COLS];
+			text[COL_DISPLAYNAME] = ADDRITEM_NAME(person);
+			text[COL_FIRSTNAME] = person->firstName;
+			text[COL_LASTNAME] = person->lastName;
+			text[COL_NICKNAME] = person->nickName;
+			row = gtk_cmclist_insert( GTK_CMCLIST(namesList), -1, text );
+			gtk_cmclist_set_row_data( GTK_CMCLIST(namesList), row, person );
+		}
+
+		g_signal_connect(G_OBJECT(namesList), "select_row",
+				G_CALLBACK(addrmerge_name_selected), page);
+	}
+
+	page->iconView = iconView;
+	page->namesList = namesList;
+
+	addrmerge_update_dialog_sensitive(page);
+	gtk_widget_show_all(dialog);
+}
+
+void addrmerge_merge(
+		GtkCMCTree *clist,
+		AddressObject *pobj,
+		AddressDataSource *ds,
+		AddrSelectList *list)
+{
+	struct AddrMergePage* page;
+	AdapterDSource *ads = NULL;
+	AddressBookFile *abf;
+	gboolean procFlag;
+	GList *node;
+	AddrSelectItem *item;
+	AddrItemObject *aio;
+	ItemPerson *person, *target = NULL, *nameTarget = NULL;
+	GList *persons = NULL, *emails = NULL;
+	gboolean pickPicture = FALSE, pickName = FALSE;
+
+	/* Test for read only */
+	if( ds->interface->readOnly ) {
+		alertpanel( _("Merge addresses"),
+			_("This address data is readonly and cannot be deleted."),
+			GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
+		return;
+	}
+
+	/* Test whether Ok to proceed */
+	procFlag = FALSE;
+	if( pobj->type == ADDR_DATASOURCE ) {
+		ads = ADAPTER_DSOURCE(pobj);
+		if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
+	}
+	else if( pobj->type == ADDR_ITEM_FOLDER ) {
+		procFlag = TRUE;
+	}
+	else if( pobj->type == ADDR_ITEM_GROUP ) {
+		procFlag = TRUE;
+	}
+	if( ! procFlag ) return;
+	abf = ds->rawDataSource;
+	if( abf == NULL ) return;
+
+	/* Gather selected persons and emails */
+	for (node = list->listSelect; node; node = node->next) {
+		item = node->data;
+		aio = ( AddrItemObject * ) item->addressItem;
+		if( aio->type == ITEMTYPE_EMAIL ) {
+			emails = g_list_prepend(emails, aio);
+		} else if( aio->type == ITEMTYPE_PERSON ) {
+			persons = g_list_prepend(persons, aio);
+		}
+	}
+
+	/* Check if more than one person has a picture */
+	for (node = persons; node; node = node->next) {
+		gchar *filename;
+		person = node->data;
+		filename = addritem_person_get_picture(person);
+		if (filename && is_file_exist(filename)) {
+			if (target == NULL) {
+				target = person;
+			} else {
+				pickPicture = TRUE;
+				target = NULL;
+				break;
+			}
+		}
+		if (filename)
+			g_free(filename);
+	}
+	if (pickPicture || target) {
+		/* At least one person had a picture */
+	} else if (persons && persons->data) {
+		/* No person had a picture. Use the first person as target */
+		target = persons->data;
+	} else {
+		/* No persons in list. Abort */
+		goto abort;
+	}
+
+	/* Pick which name to keep */
+	for (node = persons; node; node = node->next) {
+		person = node->data;
+		if (nameTarget == NULL) {
+			nameTarget = person;
+		} else if (nameTarget == person) {
+			continue;
+		} else if (strcmp2(person->firstName, nameTarget->firstName) ||
+				strcmp2(person->lastName, nameTarget->lastName) ||
+				strcmp2(person->nickName, nameTarget->nickName) ||
+				strcmp2(ADDRITEM_NAME(person), ADDRITEM_NAME(nameTarget))) {
+			pickName = TRUE;
+			break;
+		}
+	}
+	if (!nameTarget) {
+		/* No persons in list */
+		goto abort;
+	}
+
+	/* Create object */
+	page = g_new0(struct AddrMergePage, 1);
+	page->pickPicture = pickPicture;
+	page->pickName = pickName;
+	page->target = target;
+	page->nameTarget = nameTarget;
+	page->addressSelect = list;
+	page->persons = persons;
+	page->emails = emails;
+	page->clist = clist;
+	page->pobj = pobj;
+	page->abf = abf;
+	page->ds = ds;
+
+	addrmerge_prompt(page);
+	return;
+
+abort:
+	g_list_free( emails );
+	g_list_free( persons );
+}

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list