2005-07-15 [colin] 1.9.12cvs60
[claws.git] / src / addressbook.c
index 5ce8fca5441fe3befbd884132cf7b6282cfc309a..c61c571da8d9f23edfa1e091e35b24942822c83c 100644 (file)
@@ -24,6 +24,7 @@
 #include "defs.h"
 
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtkwindow.h>
 #include <gtk/gtksignal.h>
@@ -44,7 +45,6 @@
 #include <string.h>
 #include <setjmp.h>
 
-#include "intl.h"
 #include "main.h"
 #include "addressbook.h"
 #include "manage_window.h"
@@ -180,11 +180,6 @@ static void addressbook_select_row_tree            (GtkCTree       *ctree,
                                                 GtkCTreeNode   *node,
                                                 gint            column,
                                                 gpointer        data);
-static void addressbook_list_selected          (GtkCList       *clist,
-                                                gint            row,
-                                                gint            column,
-                                                GdkEvent       *event,
-                                                gpointer        data);
 static void addressbook_list_row_selected      (GtkCTree       *clist,
                                                 GtkCTreeNode   *node,
                                                 gint            column,
@@ -364,6 +359,42 @@ static void addressbook_mail_to_cb         ( void );
 static void addressbook_browse_entry_cb                ( void );
 #endif
 
+static void addressbook_start_drag(GtkWidget *widget, gint button, 
+                                  GdkEvent *event,
+                                  void *data);
+static void addressbook_drag_data_get(GtkWidget        *widget,
+                                    GdkDragContext   *drag_context,
+                                    GtkSelectionData *selection_data,
+                                    guint             info,
+                                    guint             time,
+                                    void             *data);
+static gboolean addressbook_drag_motion_cb(GtkWidget      *widget,
+                                         GdkDragContext *context,
+                                         gint            x,
+                                         gint            y,
+                                         guint           time,
+                                         void           *data);
+static void addressbook_drag_leave_cb(GtkWidget      *widget,
+                                    GdkDragContext *context,
+                                    guint           time,
+                                    void           *data);
+static void addressbook_drag_received_cb(GtkWidget        *widget,
+                                       GdkDragContext   *drag_context,
+                                       gint              x,
+                                       gint              y,
+                                       GtkSelectionData *data,
+                                       guint             info,
+                                       guint             time,
+                                       void             *pdata);
+
+static GtkTargetEntry addressbook_drag_types[] =
+{
+       {"text/plain", GTK_TARGET_SAME_APP, TARGET_DUMMY}
+};
+
+static GtkTargetList *addressbook_target_list = NULL;
+
+
 static GtkItemFactoryEntry addressbook_entries[] =
 {
        {N_("/_File"),                  NULL,           NULL, 0, "<Branch>"},
@@ -635,6 +666,7 @@ static void addressbook_create(void)
        GList *nodeIf;
 
        gchar *titles[N_COLS];
+       gchar *dummy_titles[1];
        gchar *text;
        gint i;
 
@@ -643,6 +675,7 @@ static void addressbook_create(void)
        titles[COL_NAME]    = _("Name");
        titles[COL_ADDRESS] = _("E-Mail address");
        titles[COL_REMARKS] = _("Remarks");
+       dummy_titles[0]     = "";
 
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
@@ -673,11 +706,11 @@ static void addressbook_create(void)
        ctree_swin = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
                                       GTK_POLICY_AUTOMATIC,
-                                      GTK_POLICY_ALWAYS);
+                                      GTK_POLICY_AUTOMATIC);
        gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 40, -1);
 
        /* Address index */
-       ctree = gtk_ctree_new(1, 0);
+       ctree = gtk_sctree_new_with_titles(1, 0, dummy_titles);
        gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
        gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
        gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
@@ -700,16 +733,29 @@ static void addressbook_create(void)
        g_signal_connect(G_OBJECT(ctree), "select_row",
                         G_CALLBACK(addressbook_select_row_tree), NULL);
 
+       gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
+                         addressbook_drag_types, 1,
+                         GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
+       g_signal_connect(G_OBJECT(ctree), "drag_motion",
+                        G_CALLBACK(addressbook_drag_motion_cb),
+                        ctree);
+       g_signal_connect(G_OBJECT(ctree), "drag_leave",
+                        G_CALLBACK(addressbook_drag_leave_cb),
+                        ctree);
+       g_signal_connect(G_OBJECT(ctree), "drag_data_received",
+                        G_CALLBACK(addressbook_drag_received_cb),
+                        ctree);
+
        clist_vbox = gtk_vbox_new(FALSE, 4);
 
        clist_swin = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
                                       GTK_POLICY_AUTOMATIC,
-                                      GTK_POLICY_ALWAYS);
+                                      GTK_POLICY_AUTOMATIC);
        gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
 
        /* Address list */
-       clist = gtk_ctree_new_with_titles(N_COLS, 0, titles);
+       clist = gtk_sctree_new_with_titles(N_COLS, 0, titles);
        gtk_container_add(GTK_CONTAINER(clist_swin), clist);
        gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
        gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
@@ -736,13 +782,14 @@ static void addressbook_create(void)
        g_signal_connect(G_OBJECT(clist), "button_release_event",
                         G_CALLBACK(addressbook_list_button_released),
                         NULL);
-       g_signal_connect(G_OBJECT(clist), "select_row",
-                        G_CALLBACK(addressbook_list_selected), NULL);
        g_signal_connect(G_OBJECT(clist), "tree_expand",
                         G_CALLBACK(addressbook_person_expand_node), NULL );
        g_signal_connect(G_OBJECT(clist), "tree_collapse",
                         G_CALLBACK(addressbook_person_collapse_node), NULL );
-
+       g_signal_connect(G_OBJECT(clist), "start_drag",
+                        G_CALLBACK(addressbook_start_drag), NULL);
+       g_signal_connect(G_OBJECT(clist), "drag_data_get",
+                        G_CALLBACK(addressbook_drag_data_get), NULL);  
        hbox = gtk_hbox_new(FALSE, 4);
        gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
 
@@ -869,6 +916,8 @@ static void addressbook_create(void)
        addrbook.window  = window;
        addrbook.menubar = menubar;
        addrbook.ctree   = ctree;
+       addrbook.ctree_swin
+                        = ctree_swin;
        addrbook.clist   = clist;
        addrbook.entry   = entry;
        addrbook.statusbar = statusbar;
@@ -1015,7 +1064,7 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
        if( iface->readOnly ) {
                alertpanel( _("Delete address(es)"),
                        _("This address data is readonly and cannot be deleted."),
-                       _("Close"), NULL, NULL );
+                       GTK_STOCK_CLOSE, NULL, NULL );
                return;
        }
 
@@ -1038,7 +1087,7 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
        /* Confirm deletion */
        aval = alertpanel( _("Delete address(es)"),
                        _("Really delete the address(es)?"),
-                       _("Yes"), _("No"), NULL );
+                       GTK_STOCK_YES, GTK_STOCK_NO, NULL );
        if( aval != G_ALERTDEFAULT ) return;
 
        /* Process deletions */
@@ -1066,6 +1115,8 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                        else if( aio->type == ADDR_ITEM_PERSON ) {
                                ItemPerson *item = ( ItemPerson * ) aio;
                                addressbook_folder_remove_one_person( clist, item );
+                               if (pobj->type == ADDR_ITEM_FOLDER)
+                                       addritem_folder_remove_person((ItemFolder *)pobj, item);
                                item = addrbook_remove_person( abf, item );
                                if( item ) {
                                        addritem_free_item_person( item );
@@ -1083,7 +1134,10 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                }
                g_list_free( list );
                addressbook_list_select_clear();
-               if( refreshList ) gtk_ctree_select( ctree, addrbook.opened);
+               if( refreshList ) 
+                       gtk_ctree_select( ctree, addrbook.opened);
+               addrbook_set_dirty(abf, TRUE);
+               addressbook_export_to_file();
                return;
        }
        else if( pobj->type == ADDR_ITEM_GROUP ) {
@@ -1106,6 +1160,8 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                g_list_free( list );
                addressbook_list_select_clear();
                gtk_ctree_select( ctree, addrbook.opened);
+               addrbook_set_dirty(abf, TRUE);
+               addressbook_export_to_file();
                return;
        }
 
@@ -1182,7 +1238,7 @@ static void addressbook_to_clicked(GtkButton *button, gpointer data)
        if( ! compose ) return;
 
        /* Nothing selected, but maybe there is something in text entry */
-       addr = gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
+       addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
        if ( addr ) {
                compose_entry_append(
                        compose, addr, (ComposeEntryType)data );
@@ -1503,19 +1559,6 @@ static void addressbook_list_menu_setup( void ) {
 #endif
 }
 
-static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
-                                     GdkEvent *event, gpointer data)
-{
-       if (event && event->type == GDK_2BUTTON_PRESS) {
-               /* Handle double click */
-               if (prefs_common.add_address_by_click &&
-                   addrbook.target_compose)
-                       addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
-               else
-                       addressbook_edit_address_cb(NULL, 0, NULL);
-       }
-}
-
 static void addressbook_select_row_tree        (GtkCTree       *ctree,
                                         GtkCTreeNode   *node,
                                         gint            column,
@@ -1860,7 +1903,7 @@ static void addressbook_list_row_selected( GtkCTree *clist,
 
        aio = gtk_ctree_node_get_row_data( clist, node );
        if( aio ) {
-               /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
+               printf( "list select: %d : '%s'\n", aio->type, aio->name );
                addressbook_list_select_add( aio, ds );
        }
 
@@ -1885,10 +1928,14 @@ static void addressbook_entry_gotfocus( GtkWidget *widget ) {
        gtk_editable_select_region( GTK_EDITABLE(addrbook.entry), 0, -1 );
 }
 
+/* from gdkevents.c */
+#define DOUBLE_CLICK_TIME 250
+
 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
                                                GdkEventButton *event,
                                                gpointer data)
 {
+       static guint32 lasttime = 0;
        if( ! event ) return FALSE;
 
        addressbook_list_menu_setup();
@@ -1896,7 +1943,19 @@ static gboolean addressbook_list_button_pressed(GtkWidget *widget,
        if( event->button == 3 ) {
                gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
                       event->button, event->time );
+       } else if (event->button == 1) {
+               if (event->time - lasttime < DOUBLE_CLICK_TIME) {
+                       if (prefs_common.add_address_by_click &&
+                           addrbook.target_compose)
+                               addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
+                       else
+                               addressbook_edit_address_cb(NULL, 0, NULL);
+
+                       lasttime = 0;
+               } else
+                       lasttime = event->time;
        }
+
        return FALSE;
 }
 
@@ -2315,23 +2374,20 @@ static void addressbook_treenode_delete_cb(
                                "results and addresses in `%s' ?" ),
                                obj->name );
                        aval = alertpanel( _("Delete"), message,
-                               _("Yes"), _("No"), NULL );
+                               GTK_STOCK_YES, GTK_STOCK_NO, NULL );
                        g_free(message);
                        if( aval == G_ALERTDEFAULT ) {
                                delType = ADDRTREE_DEL_FOLDER_ADDR;
                        }
                }
                else {
-                       message = g_strdup_printf( _(
-                               "Do you want to delete the folder " \
-                               "AND all addresses in `%s' ? \n" \
-                               "If deleting the folder only, addresses " \
-                               "will be moved into parent folder." ),
-                               obj->name );
-                       aval = alertpanel( _("Delete"), message,
-                               _("Folder only"),
-                               _("Folder and Addresses"),
-                               _("Cancel") );
+                       message = g_strdup_printf
+                               ( _( "Do you want to delete the folder AND all addresses in `%s' ?\n"
+                                    "If deleting the folder only, addresses will be moved into parent folder." ),
+                                obj->name );
+                       aval = alertpanel( _("Delete folder"), message,
+                               _("_Folder only"), _("Folder and _addresses"),
+                               GTK_STOCK_CANCEL );
                        g_free(message);
                        if( aval == G_ALERTDEFAULT ) {
                                delType = ADDRTREE_DEL_FOLDER_ONLY;
@@ -2343,7 +2399,7 @@ static void addressbook_treenode_delete_cb(
        }
        else {
                message = g_strdup_printf(_("Really delete `%s' ?"), obj->name);
-               aval = alertpanel(_("Delete"), message, _("Yes"), _("No"), NULL);
+               aval = alertpanel(_("Delete"), message, GTK_STOCK_YES, GTK_STOCK_NO, NULL);
                g_free(message);
                if( aval == G_ALERTDEFAULT ) delType = ADDRTREE_DEL_DATA;
        }
@@ -2506,6 +2562,16 @@ static AddressBookFile *addressbook_get_book_file() {
        return abf;
 }
 
+static AddressBookFile *addressbook_get_book_file_for_node(GtkCTreeNode *node) {
+       AddressBookFile *abf = NULL;
+       AddressDataSource *ds = NULL;
+
+       ds = addressbook_find_datasource( node );
+       if( ds == NULL ) return NULL;
+       if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
+       return abf;
+}
+
 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
        GtkCTreeNode *node;
        GtkCTreeRow *row;
@@ -2749,7 +2815,6 @@ static void addressbook_folder_load_one_person(
                                FALSE, person->isOpened );
                gtk_ctree_node_set_row_data(clist, nodePerson, person );
        }
-       gtk_sctree_sort_node(GTK_CTREE(clist), NULL);
        return;
 }
 
@@ -3007,7 +3072,7 @@ static void addressbook_set_clist( AddressObject *obj ) {
                        addressbook_folder_load_group( ctreelist, itemFolder );
                }
        }
-       /* gtk_clist_sort(clist); */
+       gtk_sctree_sort_node(GTK_CTREE(clist), NULL);
        gtk_clist_thaw(clist);
 }
 
@@ -3177,12 +3242,12 @@ static gboolean addressbook_convert( AddressIndex *addrIndex ) {
        }
        if( errFlag ) {
                debug_print( "Error\n%s\n", msg );
-               alertpanel_with_type( _( "Addressbook conversion error" ), msg, _( "Close" )
+               alertpanel_with_type( _( "Addressbook conversion error" ), msg, GTK_STOCK_CLOSE
                                      NULL, NULL, NULL, ALERT_ERROR );
        }
        else if( msg ) {
                debug_print( "Warning\n%s\n", msg );
-               alertpanel_with_type( _( "Addressbook conversion" ), msg, _( "Close" )
+               alertpanel_with_type( _( "Addressbook conversion" ), msg, GTK_STOCK_CLOSE
                                      NULL, NULL, NULL, ALERT_WARNING );
        }
 
@@ -3221,7 +3286,7 @@ void addressbook_read_file( void ) {
                addrindex_print_index( addrIndex, stdout );
                alertpanel_with_type( _( "Addressbook Error" ),
                            _( "Could not read address index" ),
-                           _( "Close" ), NULL, NULL, NULL,
+                           GTK_STOCK_CLOSE, NULL, NULL, NULL,
                            ALERT_ERROR);
        }
        debug_print( "done.\n" );
@@ -3422,7 +3487,7 @@ static gint addressbook_treenode_compare_func(
        if( cell2 ) name2 = cell2->u.text;
        if( ! name1 ) return ( name2 != NULL );
        if( ! name2 ) return -1;
-       return strcasecmp( name1, name2 );
+       return g_utf8_collate( name1, name2 );
 }
 
 /*
@@ -3443,7 +3508,7 @@ static gint addressbook_list_compare_func(
                /* Order by name */
                if( ! name1 ) return ( name2 != NULL );
                if( ! name2 ) return -1;
-               return strcasecmp( name1, name2 );
+               return g_utf8_collate( name1, name2 );
        }
        else {
                /* Order groups before person */
@@ -3671,7 +3736,7 @@ static void addressbook_perform_search(
        gchar *name;
        gint queryID;
        guint idleID;
-       AddressObjectType aoType;
+       AddressObjectType aoType = ADDR_NONE;
 
        /* Setup a query */
        if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
@@ -4433,6 +4498,257 @@ static void addressbook_export_ldif_cb( void ) {
        addressbook_exp_ldif( cache );
 }
 
+static void addressbook_start_drag(GtkWidget *widget, gint button, 
+                                  GdkEvent *event,
+                                  void *data)
+{
+       GdkDragContext *context;
+       if (addressbook_target_list == NULL)
+               addressbook_target_list = gtk_target_list_new(
+                               addressbook_drag_types, 1);
+       context = gtk_drag_begin(widget, addressbook_target_list,
+                                GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
+       gtk_drag_set_icon_default(context);
+}
+
+static GSList *dragged_persons = NULL;
+static ItemFolder *dragged_folder = NULL;
+static AddressBookFile *dragged_ab = NULL;
+
+static void addressbook_drag_data_get(GtkWidget        *widget,
+                                    GdkDragContext   *drag_context,
+                                    GtkSelectionData *selection_data,
+                                    guint             info,
+                                    guint             time,
+                                    void             *data)
+{
+       AddrItemObject *aio = NULL;
+       AddressObject *pobj = NULL;
+       AdapterDSource *ads = NULL;
+       AddressDataSource *ds = NULL;
+       GList *cur;
+
+       pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
+       if( pobj == NULL ) return;
+
+       if( pobj->type == ADDR_DATASOURCE ) {
+               ads = ADAPTER_DSOURCE(pobj);
+               ds = ads->dataSource;
+       } else if (pobj->type == ADDR_ITEM_GROUP) {
+               return;
+       }
+       
+       else if( pobj->type != ADDR_INTERFACE ) {
+               ds = addressbook_find_datasource( addrbook.treeSelected );
+               if (!ds)
+                       return;
+       }
+       
+
+       for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
+               aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist), 
+                       GTK_CTREE_NODE(cur->data));
+               while (aio && aio->type != ADDR_ITEM_PERSON) {
+                       aio = aio->parent;
+               }
+               if (aio) {
+                       dragged_persons = g_slist_append(dragged_persons, aio);
+               }
+       }
+
+       if (aio && aio->type == ADDR_ITEM_PERSON) {
+               dragged_folder = (ItemFolder *)ADAPTER_FOLDER(pobj)->itemFolder;
+               dragged_ab = addressbook_get_book_file();
+
+               gtk_selection_data_set(selection_data,
+                                      selection_data->target, 8,
+                                      "Dummy_addr", 11);
+               drag_context->actions = GDK_ACTION_MOVE;
+               
+               if (pobj->type == ADDR_DATASOURCE) {
+                       if( ds != NULL) {
+                               dragged_folder = addrindex_ds_get_root_folder( ds );
+                               if (ds->type != ADDR_IF_JPILOT ||
+                                   ds->type != ADDR_IF_LDAP)
+                                   drag_context->action = GDK_ACTION_COPY;
+                       } else {
+                               dragged_folder = NULL;
+                               g_slist_free(dragged_persons);
+                               dragged_persons = NULL;
+                               dragged_ab = NULL;
+                       }
+               }
+       } else {
+               dragged_folder = NULL;
+               g_slist_free(dragged_persons);
+               dragged_persons = NULL;
+               dragged_ab = NULL;
+       }
+}
+
+static gboolean addressbook_drag_motion_cb(GtkWidget      *widget,
+                                         GdkDragContext *context,
+                                         gint            x,
+                                         gint            y,
+                                         guint           time,
+                                         void            *data)
+{
+       gint row, column;
+       GtkCTreeNode *node = NULL;
+       gboolean acceptable = FALSE;
+       gint height = addrbook.ctree->allocation.height;
+       gint total_height = addrbook.ctree->requisition.height;
+       GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
+                               GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
+       gfloat vpos = pos->value;
+       
+       if (gtk_clist_get_selection_info
+               (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
+
+               if (y > height - 24 && height + vpos < total_height)
+                       gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
+
+               if (y < 24 && y > 0)
+                       gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
+
+               node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
+
+               if (node != NULL) {
+                       AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
+                       if( obj->type == ADDR_ITEM_FOLDER 
+                       || obj->type == ADDR_ITEM_GROUP)
+                               acceptable = TRUE;
+                       else {
+                               AdapterDSource *ads = NULL;
+                               AddressDataSource *ds = NULL;
+                               ads = ADAPTER_DSOURCE(obj);
+                               if (ads == NULL ) return FALSE;
+                               ds = ads->dataSource;
+                               if (ds == NULL ) return FALSE;
+                               if (obj->type == ADDR_DATASOURCE
+                               &&  !ds->interface->externalQuery)
+                                       acceptable = TRUE;
+
+                       }
+               }
+       }
+
+       
+       if (acceptable) {
+               g_signal_handlers_block_by_func
+                       (G_OBJECT(widget),
+                        G_CALLBACK(addressbook_tree_selected), NULL);
+               gtk_ctree_select(GTK_CTREE(widget), node);
+               g_signal_handlers_unblock_by_func
+                       (G_OBJECT(widget),
+                        G_CALLBACK(addressbook_tree_selected), NULL);
+               gdk_drag_status(context, 
+                                       (context->actions == GDK_ACTION_COPY ?
+                                       GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
+       } else {
+               gdk_drag_status(context, 0, time);
+       }
+
+       return acceptable;
+}
+
+static void addressbook_drag_leave_cb(GtkWidget      *widget,
+                                    GdkDragContext *context,
+                                    guint           time,
+                                    void           *data)
+{
+       if (addrbook.treeSelected) {
+               g_signal_handlers_block_by_func
+                       (G_OBJECT(widget),
+                        G_CALLBACK(addressbook_tree_selected), NULL);
+               gtk_ctree_select(GTK_CTREE(widget), addrbook.treeSelected);
+               g_signal_handlers_unblock_by_func
+                       (G_OBJECT(widget),
+                        G_CALLBACK(addressbook_tree_selected), NULL);
+       }
+}
+
+static void addressbook_drag_received_cb(GtkWidget        *widget,
+                                       GdkDragContext   *drag_context,
+                                       gint              x,
+                                       gint              y,
+                                       GtkSelectionData *data,
+                                       guint             info,
+                                       guint             time,
+                                       void             *pdata)
+{
+       gint row, column;
+       GtkCTreeNode *node;
+       ItemFolder *afolder = NULL;
+       ItemFolder *ofolder = NULL;
+       ItemPerson *person = NULL;
+       
+
+       if (!strcmp(data->data, "Dummy_addr")) {
+               AddressObject *obj = NULL;
+               AdapterDSource *ads = NULL;
+               AddressDataSource *ds = NULL;
+               GSList *cur = dragged_persons;
+
+               if (gtk_clist_get_selection_info
+                       (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
+                       goto free_list;
+               }
+       
+               node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
+               if( node ) 
+                       obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node );
+               if( obj == NULL ) 
+                       goto free_list;
+                               
+               if (obj->type == ADDR_ITEM_FOLDER) {
+                       afolder = ADAPTER_FOLDER(obj)->itemFolder;
+
+               } else if (obj->type == ADDR_DATASOURCE) {
+                       ads = ADAPTER_DSOURCE(obj);
+                       if( ads == NULL ) 
+                               goto free_list;
+                       ds = ads->dataSource;
+                       if( ds == NULL ||
+                           ds->type == ADDR_IF_JPILOT || 
+                           ds->type == ADDR_IF_LDAP) 
+                               goto free_list;         
+                       afolder = addrindex_ds_get_root_folder( ds );
+                       
+               } else {
+                       goto free_list;
+               }
+
+               ofolder = dragged_folder;
+               
+               if (afolder && ofolder) {
+                       AddressBookFile *obook = dragged_ab;
+                       AddressBookFile *abook = addressbook_get_book_file_for_node(node);
+                       for (cur = dragged_persons; cur; cur = cur->next) {
+                               person = (ItemPerson *)cur->data;
+                               addritem_folder_remove_person(ofolder, person);
+                               addritem_folder_add_person(afolder, person);
+                       }
+                       addressbook_list_select_clear();
+                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened);
+                                                       
+                       if (abook) {
+                               addrbook_set_dirty(abook, TRUE);
+                       }
+                       if (obook) {
+                               addrbook_set_dirty(obook, TRUE);
+                       }
+                       
+                       addressbook_export_to_file();
+               }
+
+               gtk_drag_finish(drag_context, TRUE, TRUE, time);
+       }
+free_list:
+       g_slist_free(dragged_persons);
+       dragged_persons = NULL;
+}
+
 /*
 * End of Source.
 */