2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
55 #include "stock_pixmap.h"
57 #include "prefs_gtk.h"
63 #include "addr_compl.h"
66 #include "addressitem.h"
68 #include "addrcache.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addressbook_foldersel.h"
74 #include "editvcard.h"
75 #include "editgroup.h"
76 #include "editaddress.h"
78 #include "importldif.h"
79 #include "importmutt.h"
80 #include "importpine.h"
85 #include "editjpilot.h"
90 #include "ldapserver.h"
93 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
96 #include "addrquery.h"
97 #include "addrselect.h"
99 #include "addrgather.h"
100 #include "adbookbase.h"
101 #include "exphtmldlg.h"
102 #include "expldifdlg.h"
103 #include "browseldap.h"
109 } AddressIndexColumns;
117 } AddressListColumns;
120 AddressBookFile *book;
128 AddressDataSource *book;
132 static gchar *list_titles[] = { N_("Name"),
136 #define COL_NAME_WIDTH 164
137 #define COL_ADDRESS_WIDTH 156
139 #define COL_FOLDER_WIDTH 170
140 #define ADDRESSBOOK_WIDTH 640
141 #define ADDRESSBOOK_HEIGHT 360
143 #define ADDRESSBOOK_MSGBUF_SIZE 2048
145 static GdkPixmap *folderxpm;
146 static GdkBitmap *folderxpmmask;
147 static GdkPixmap *folderopenxpm;
148 static GdkBitmap *folderopenxpmmask;
149 static GdkPixmap *groupxpm;
150 static GdkBitmap *groupxpmmask;
151 static GdkPixmap *interfacexpm;
152 static GdkBitmap *interfacexpmmask;
153 static GdkPixmap *bookxpm;
154 static GdkBitmap *bookxpmmask;
155 static GdkPixmap *addressxpm;
156 static GdkBitmap *addressxpmmask;
157 static GdkPixmap *vcardxpm;
158 static GdkBitmap *vcardxpmmask;
159 static GdkPixmap *jpilotxpm;
160 static GdkBitmap *jpilotxpmmask;
161 static GdkPixmap *categoryxpm;
162 static GdkBitmap *categoryxpmmask;
163 static GdkPixmap *ldapxpm;
164 static GdkBitmap *ldapxpmmask;
165 static GdkPixmap *addrsearchxpm;
166 static GdkPixmap *addrsearchxpmmask;
169 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
171 /* Address list selection */
172 static AddrSelectList *_addressSelect_ = NULL;
173 static AddressClipboard *_clipBoard_ = NULL;
175 /* Address index file and interfaces */
176 static AddressIndex *_addressIndex_ = NULL;
177 static GList *_addressInterfaceList_ = NULL;
178 static GList *_addressIFaceSelection_ = NULL;
179 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
181 static AddressBook_win addrbook;
183 static GHashTable *_addressBookTypeHash_ = NULL;
184 static GList *_addressBookTypeList_ = NULL;
186 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
187 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
188 static void addressbook_edit_address_post_cb( ItemPerson *person );
190 static void addressbook_create (void);
191 static gint addressbook_close (void);
192 static void addressbook_button_set_sensitive (void);
194 static gboolean address_index_has_focus = FALSE;
195 static gboolean address_list_has_focus = FALSE;
197 /* callback functions */
198 static void addressbook_del_clicked (GtkButton *button,
200 static void addressbook_reg_clicked (GtkButton *button,
202 static void addressbook_to_clicked (GtkButton *button,
204 static void addressbook_lup_clicked (GtkButton *button,
206 static void addressbook_close_clicked (GtkButton *button,
209 static void addressbook_tree_selected (GtkCTree *ctree,
213 static void addressbook_select_row_tree (GtkCTree *ctree,
217 static void addressbook_list_row_selected (GtkCTree *clist,
221 static void addressbook_list_row_unselected (GtkCTree *clist,
225 static void addressbook_person_expand_node (GtkCTree *ctree,
228 static void addressbook_person_collapse_node (GtkCTree *ctree,
232 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
233 GdkEventButton *event,
235 static gboolean addressbook_list_button_released(GtkWidget *widget,
236 GdkEventButton *event,
238 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
239 GdkEventButton *event,
241 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
242 GdkEventButton *event,
245 static void addressbook_new_folder_cb (gpointer data,
248 static void addressbook_new_group_cb (gpointer data,
251 static void addressbook_treenode_edit_cb (gpointer data,
254 static void addressbook_treenode_delete_cb (gpointer data,
258 static void addressbook_change_node_name (GtkCTreeNode *node,
261 static void addressbook_new_address_cb (gpointer data,
264 static void addressbook_edit_address_cb (gpointer data,
267 static void addressbook_delete_address_cb (gpointer data,
271 static void close_cb (gpointer data,
274 static void addressbook_file_save_cb (gpointer data,
278 /* Data source edit stuff */
279 static void addressbook_new_book_cb (gpointer data,
282 static void addressbook_new_vcard_cb (gpointer data,
287 static void addressbook_new_jpilot_cb (gpointer data,
293 static void addressbook_new_ldap_cb (gpointer data,
298 static void addressbook_set_clist (AddressObject *obj,
301 static void addressbook_load_tree (void);
302 void addressbook_read_file (void);
304 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
306 static void addressbook_treenode_remove_item ( void );
308 static AddressDataSource *addressbook_find_datasource
309 (GtkCTreeNode *node );
311 static AddressBookFile *addressbook_get_book_file(void);
313 static GtkCTreeNode *addressbook_node_add_folder
315 AddressDataSource *ds,
316 ItemFolder *itemFolder,
317 AddressObjectType otype);
318 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
319 AddressDataSource *ds,
320 ItemGroup *itemGroup);
321 static void addressbook_tree_remove_children (GtkCTree *ctree,
322 GtkCTreeNode *parent);
323 static void addressbook_move_nodes_up (GtkCTree *ctree,
325 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
327 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
330 static gint addressbook_treenode_compare_func (GtkCList *clist,
333 static void addressbook_folder_load_one_person (GtkCTree *clist,
335 AddressTypeControlItem *atci,
336 AddressTypeControlItem *atciMail);
337 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
339 static void addressbook_folder_remove_one_person(GtkCTree *clist,
341 static void addressbook_folder_remove_node (GtkCTree *clist,
344 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
345 gboolean force_focus );
347 /* LUT's and IF stuff */
348 static void addressbook_free_treenode ( gpointer data );
349 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
350 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
352 static void addrbookctl_build_map (GtkWidget *window);
353 static void addrbookctl_build_iflist (void);
354 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
355 static void addrbookctl_build_ifselect (void);
357 static void addrbookctl_free_interface (AdapterInterface *adapter);
358 static void addrbookctl_free_datasource (AdapterDSource *adapter);
359 static void addrbookctl_free_folder (AdapterFolder *adapter);
360 static void addrbookctl_free_group (AdapterGroup *adapter);
362 static void addressbook_list_select_clear ( void );
363 static void addressbook_list_select_add ( AddrItemObject *aio,
364 AddressDataSource *ds );
365 static void addressbook_list_select_remove ( AddrItemObject *aio );
367 static void addressbook_import_ldif_cb ( void );
368 static void addressbook_import_mutt_cb ( void );
369 static void addressbook_import_pine_cb ( void );
370 static void addressbook_export_html_cb ( void );
371 static void addressbook_export_ldif_cb ( void );
372 static void addressbook_select_all_cb ( void );
373 static void addressbook_clip_cut_cb ( void );
374 static void addressbook_clip_copy_cb ( void );
375 static void addressbook_clip_paste_cb ( void );
376 static void addressbook_treenode_cut_cb ( void );
377 static void addressbook_treenode_copy_cb ( void );
378 static void addressbook_treenode_paste_cb ( void );
380 static void addressbook_mail_to_cb ( void );
383 static void addressbook_browse_entry_cb ( void );
385 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
387 static void addressbook_start_drag(GtkWidget *widget, gint button,
390 static void addressbook_drag_data_get(GtkWidget *widget,
391 GdkDragContext *drag_context,
392 GtkSelectionData *selection_data,
396 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
397 GdkDragContext *context,
402 static void addressbook_drag_leave_cb(GtkWidget *widget,
403 GdkDragContext *context,
406 static void addressbook_drag_received_cb(GtkWidget *widget,
407 GdkDragContext *drag_context,
410 GtkSelectionData *data,
414 static void addressbook_list_menu_setup( void );
416 static GtkTargetEntry addressbook_drag_types[] =
418 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
421 static GtkTargetList *addressbook_target_list = NULL;
424 static GtkItemFactoryEntry addressbook_entries[] =
426 {N_("/_Book"), NULL, NULL, 0, "<Branch>"},
427 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL},
428 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL},
429 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL},
431 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL},
434 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL},
436 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
437 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL},
438 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL},
439 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
440 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL},
441 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL},
442 {N_("/_Address"), NULL, NULL, 0, "<Branch>"},
443 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL},
444 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
445 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL},
446 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL},
447 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL},
448 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
449 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL},
450 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL},
451 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
452 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL},
453 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL},
454 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
455 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
456 {N_("/_Tools"), NULL, NULL, 0, "<Branch>"},
457 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL},
458 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL},
459 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL},
460 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
461 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL},
462 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL},
463 {N_("/_Help"), NULL, NULL, 0, "<Branch>"},
464 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
467 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
469 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL},
470 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL},
471 {"/---", NULL, NULL, 0, "<Separator>"},
472 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL},
473 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
474 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
475 {"/---", NULL, NULL, 0, "<Separator>"},
476 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL},
477 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL},
478 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL}
481 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
483 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL},
484 {"/---", NULL, NULL, 0, "<Separator>"},
485 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
486 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
487 {"/---", NULL, NULL, 0, "<Separator>"},
488 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
489 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
490 {"/---", NULL, NULL, 0, "<Separator>"},
491 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL},
492 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL},
493 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL},
494 {"/---", NULL, NULL, 0, "<Separator>"},
495 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},*/
496 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
498 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL},
503 * Structure of error message table.
505 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
506 struct _ErrMsgTableEntry {
511 static gchar *_errMsgUnknown_ = N_( "Unknown" );
514 * Lookup table of error messages for general errors. Note that a NULL
515 * description signifies the end of the table.
517 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
518 { MGU_SUCCESS, N_("Success") },
519 { MGU_BAD_ARGS, N_("Bad arguments") },
520 { MGU_NO_FILE, N_("File not specified") },
521 { MGU_OPEN_FILE, N_("Error opening file") },
522 { MGU_ERROR_READ, N_("Error reading file") },
523 { MGU_EOF, N_("End of file encountered") },
524 { MGU_OO_MEMORY, N_("Error allocating memory") },
525 { MGU_BAD_FORMAT, N_("Bad file format") },
526 { MGU_ERROR_WRITE, N_("Error writing to file") },
527 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
528 { MGU_NO_PATH, N_("No path specified") },
534 * Lookup table of error messages for LDAP errors.
536 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
537 { LDAPRC_SUCCESS, N_("Success") },
538 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
539 { LDAPRC_INIT, N_("Error initializing LDAP") },
540 { LDAPRC_BIND, N_("Error binding to LDAP server") },
541 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
542 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
543 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
544 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
545 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
546 { LDAPRC_TLS, N_("Error starting TLS connection") },
552 * Lookup message for specified error code.
553 * \param lut Lookup table.
554 * \param code Code to lookup.
555 * \return Description associated to code.
557 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
559 ErrMsgTableEntry entry;
562 for( i = 0; ; i++ ) {
564 if( entry.description == NULL ) break;
565 if( entry.code == code ) {
566 desc = entry.description;
571 desc = _errMsgUnknown_;
576 static gboolean lastCanLookup = FALSE;
578 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
580 if (add_and_delete) {
581 gtk_widget_show(addrbook.edit_btn);
582 gtk_widget_show(addrbook.del_btn);
583 gtk_widget_show(addrbook.reg_btn);
585 gtk_widget_hide(addrbook.edit_btn);
586 gtk_widget_hide(addrbook.del_btn);
587 gtk_widget_hide(addrbook.reg_btn);
591 gtk_widget_show(addrbook.lup_btn);
592 gtk_widget_show(addrbook.entry);
593 gtk_widget_show(addrbook.label);
595 gtk_widget_hide(addrbook.lup_btn);
596 gtk_widget_hide(addrbook.entry);
597 gtk_widget_hide(addrbook.label);
600 lastCanLookup = lookup;
603 gtk_widget_show(addrbook.to_btn);
604 gtk_widget_show(addrbook.cc_btn);
605 gtk_widget_show(addrbook.bcc_btn);
607 gtk_widget_hide(addrbook.to_btn);
608 gtk_widget_hide(addrbook.cc_btn);
609 gtk_widget_hide(addrbook.bcc_btn);
613 void addressbook_open(Compose *target)
615 /* Initialize all static members */
616 if( _clipBoard_ == NULL ) {
617 _clipBoard_ = addrclip_create();
619 if( _addressIndex_ != NULL ) {
620 addrclip_set_index( _clipBoard_, _addressIndex_ );
622 if( _addressSelect_ == NULL ) {
623 _addressSelect_ = addrselect_list_create();
625 if (!addrbook.window) {
626 addressbook_read_file();
627 addressbook_create();
628 addressbook_load_tree();
629 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
630 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
633 gtk_widget_hide(addrbook.window);
636 gtk_widget_show_all(addrbook.window);
638 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
639 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
641 if (!prefs_common.addressbook_use_editaddress_dialog)
642 addressbook_edit_person_widgetset_hide();
644 address_completion_start(addrbook.window);
646 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
647 addressbook_set_target_compose(target);
651 * Destroy addressbook.
653 void addressbook_destroy( void ) {
654 /* Free up address stuff */
655 if( _addressSelect_ != NULL ) {
656 addrselect_list_free( _addressSelect_ );
658 if( _clipBoard_ != NULL ) {
659 addrclip_free( _clipBoard_ );
661 if( _addressIndex_ != NULL ) {
662 addrindex_free_index( _addressIndex_ );
663 addrindex_teardown();
665 _addressSelect_ = NULL;
667 _addressIndex_ = NULL;
670 void addressbook_set_target_compose(Compose *target)
672 addrbook.target_compose = target;
673 addressbook_button_set_sensitive();
676 Compose *addressbook_get_target_compose(void)
678 return addrbook.target_compose;
682 * Refresh addressbook and save to file(s).
684 static void addressbook_refresh( void )
686 if (addrbook.window) {
687 if (addrbook.treeSelected) {
688 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
689 addrbook.treeSelected);
690 addressbook_set_clist(
691 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
692 addrbook.treeSelected),
697 addressbook_export_to_file();
700 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
702 if (event && event->keyval == GDK_Escape)
704 else if (event && event->keyval == GDK_Delete) {
705 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
706 if ( /* address_index_has_focus || */ address_list_has_focus )
707 addressbook_del_clicked(NULL, NULL);
713 *\brief Save Gtk object size to prefs dataset
715 static void addressbook_size_allocate_cb(GtkWidget *widget,
716 GtkAllocation *allocation)
718 g_return_if_fail(allocation != NULL);
720 prefs_common.addressbookwin_width = allocation->width;
721 prefs_common.addressbookwin_height = allocation->height;
724 static gint sort_column_number = 0;
725 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
727 static gint list_case_sort(
728 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
730 GtkCListRow *row1 = (GtkCListRow *) ptr1;
731 GtkCListRow *row2 = (GtkCListRow *) ptr2;
732 gchar *name1 = NULL, *name2 = NULL;
733 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
734 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
736 if( aio1->type == aio2->type ) {
738 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
740 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
741 if( ! name1 ) return ( name2 != NULL );
742 if( ! name2 ) return -1;
743 return strcasecmp( name1, name2 );
745 /* Order groups before person */
746 if( aio1->type == ITEMTYPE_GROUP ) {
747 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
748 } else if( aio2->type == ITEMTYPE_GROUP ) {
749 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
755 static void addressbook_sort_list(GtkCList *clist, const gint col,
756 const GtkSortType sort_type)
759 GtkWidget *hbox, *label, *arrow;
761 sort_column_number = col;
762 sort_column_type = sort_type;
763 gtk_clist_set_compare_func(clist, list_case_sort);
764 gtk_clist_set_sort_type(clist, sort_type);
765 gtk_clist_set_sort_column(clist, col);
767 gtk_clist_freeze(clist);
768 gtk_clist_sort(clist);
770 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
771 hbox = gtk_hbox_new(FALSE, 4);
772 label = gtk_label_new(gettext(list_titles[pos]));
773 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
776 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
777 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
778 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
781 gtk_widget_show_all(hbox);
782 gtk_clist_set_column_widget(clist, pos, hbox);
785 gtk_clist_thaw(clist);
788 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
790 static GtkSortType sort_type = GTK_SORT_ASCENDING;
792 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
794 addressbook_sort_list(clist, COL_NAME, sort_type);
797 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
799 static GtkSortType sort_type = GTK_SORT_ASCENDING;
801 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
803 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
806 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
808 static GtkSortType sort_type = GTK_SORT_ASCENDING;
810 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
812 addressbook_sort_list(clist, COL_REMARKS, sort_type);
815 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
818 address_index_has_focus = TRUE;
822 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
825 address_index_has_focus = FALSE;
826 if (!prefs_common.addressbook_use_editaddress_dialog
827 && !address_list_has_focus)
828 addressbook_address_list_disable_some_actions();
832 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
835 address_list_has_focus = TRUE;
839 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
842 address_list_has_focus = FALSE;
843 if (!prefs_common.addressbook_use_editaddress_dialog
844 && !address_index_has_focus)
845 addressbook_address_list_disable_some_actions();
849 /* save hpane and vpane's handle position when it moves */
850 static void addressbook_pane_save_position(void)
853 prefs_common.addressbook_hpaned_pos =
854 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
856 prefs_common.addressbook_vpaned_pos =
857 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
861 * Create the address book widgets. The address book contains two CTree widgets: the
862 * address index tree on the left and the address list on the right.
864 * The address index tree displays a hierarchy of interfaces and groups. Each node in
865 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
866 * data sources and folder objects.
868 * The address list displays group, person and email objects. These items are linked
869 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
872 * In the tradition of MVC architecture, the data stores have been separated from the
873 * GUI components. The addrindex.c file provides the interface to all data stores.
875 static void addressbook_create(void)
881 GtkWidget *ctree_swin;
883 GtkWidget *editaddress_vbox;
884 GtkWidget *clist_vbox;
885 GtkWidget *clist_swin;
892 GtkWidget *statusbar;
903 GtkWidget *close_btn;
904 GtkWidget *tree_popup;
905 GtkWidget *list_popup;
906 GtkItemFactory *tree_factory;
907 GtkItemFactory *list_factory;
908 GtkItemFactory *menu_factory;
912 gchar *index_titles[N_INDEX_COLS];
916 static GdkGeometry geometry;
918 debug_print("Creating addressbook window...\n");
920 index_titles[COL_SOURCES] = _("Sources");
922 /* Address book window */
923 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
924 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
925 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
926 gtk_widget_realize(window);
928 g_signal_connect(G_OBJECT(window), "delete_event",
929 G_CALLBACK(addressbook_close), NULL);
930 g_signal_connect(G_OBJECT(window), "size_allocate",
931 G_CALLBACK(addressbook_size_allocate_cb), NULL);
932 g_signal_connect(G_OBJECT(window), "key_press_event",
933 G_CALLBACK(key_pressed), NULL);
934 MANAGE_WINDOW_SIGNALS_CONNECT(window);
936 vbox = gtk_vbox_new(FALSE, 0);
937 gtk_container_add(GTK_CONTAINER(window), vbox);
940 n_entries = sizeof(addressbook_entries) /
941 sizeof(addressbook_entries[0]);
942 menubar = menubar_create(window, addressbook_entries, n_entries,
943 "<AddressBook>", NULL);
944 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
945 menu_factory = gtk_item_factory_from_widget(menubar);
947 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
948 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
949 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
951 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
952 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
953 GTK_POLICY_AUTOMATIC,
954 GTK_POLICY_AUTOMATIC);
955 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
958 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
959 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
960 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
961 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
962 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
963 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
964 GTK_CTREE_EXPANDER_SQUARE);
965 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
966 gtk_clist_set_compare_func(GTK_CLIST(ctree),
967 addressbook_treenode_compare_func);
969 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
970 G_CALLBACK(addressbook_tree_selected), NULL);
971 g_signal_connect(G_OBJECT(ctree), "button_press_event",
972 G_CALLBACK(addressbook_tree_button_pressed),
974 g_signal_connect(G_OBJECT(ctree), "button_release_event",
975 G_CALLBACK(addressbook_tree_button_released),
978 g_signal_connect(G_OBJECT(ctree), "select_row",
979 G_CALLBACK(addressbook_select_row_tree), NULL);
981 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
982 addressbook_drag_types, 1,
983 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
984 g_signal_connect(G_OBJECT(ctree), "drag_motion",
985 G_CALLBACK(addressbook_drag_motion_cb),
987 g_signal_connect(G_OBJECT(ctree), "drag_leave",
988 G_CALLBACK(addressbook_drag_leave_cb),
990 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
991 G_CALLBACK(addressbook_drag_received_cb),
993 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
994 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
995 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
996 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
998 clist_vbox = gtk_vbox_new(FALSE, 4);
1000 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1001 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1002 GTK_POLICY_AUTOMATIC,
1003 GTK_POLICY_AUTOMATIC);
1004 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1007 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1008 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1009 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1010 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1011 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1012 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1013 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1015 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1017 gtk_widget_set_size_request(clist, -1, 80);
1019 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1020 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1021 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1022 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1023 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1024 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1025 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1026 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1027 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1028 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1029 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1031 for (i = 0; i < N_LIST_COLS; i++)
1032 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1035 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1036 G_CALLBACK(addressbook_list_row_selected), NULL);
1037 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1038 G_CALLBACK(addressbook_list_row_unselected), NULL);
1039 g_signal_connect(G_OBJECT(clist), "button_press_event",
1040 G_CALLBACK(addressbook_list_button_pressed),
1042 g_signal_connect(G_OBJECT(clist), "button_release_event",
1043 G_CALLBACK(addressbook_list_button_released),
1045 g_signal_connect(G_OBJECT(clist), "tree_expand",
1046 G_CALLBACK(addressbook_person_expand_node), NULL );
1047 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1048 G_CALLBACK(addressbook_person_collapse_node), NULL );
1049 g_signal_connect(G_OBJECT(clist), "start_drag",
1050 G_CALLBACK(addressbook_start_drag), NULL);
1051 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1052 G_CALLBACK(addressbook_drag_data_get), NULL);
1053 hbox = gtk_hbox_new(FALSE, 4);
1054 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1056 label = gtk_label_new(_("Lookup name:"));
1057 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1059 entry = gtk_entry_new();
1060 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1062 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1064 g_signal_connect(G_OBJECT(entry), "key_press_event",
1065 G_CALLBACK(addressbook_entry_key_pressed),
1068 if (!prefs_common.addressbook_use_editaddress_dialog) {
1069 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1070 vpaned = gtk_vpaned_new();
1071 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1072 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1075 editaddress_vbox = NULL;
1077 hpaned = gtk_hpaned_new();
1078 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1079 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1080 if (prefs_common.addressbook_use_editaddress_dialog)
1081 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1083 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1086 hsbox = gtk_hbox_new(FALSE, 0);
1087 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1088 statusbar = gtk_statusbar_new();
1089 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1092 hbbox = gtk_hbutton_box_new();
1093 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1094 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1095 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1096 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1098 gtkut_stock_button_add_help(hbbox, &help_btn);
1100 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1101 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1102 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1103 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1104 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1105 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1106 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1107 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1108 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1111 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1112 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1113 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1115 g_signal_connect(G_OBJECT(help_btn), "clicked",
1116 G_CALLBACK(manual_open_with_anchor_cb),
1117 MANUAL_ANCHOR_ADDRBOOK);
1119 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1120 G_CALLBACK(addressbook_edit_clicked), NULL);
1121 g_signal_connect(G_OBJECT(del_btn), "clicked",
1122 G_CALLBACK(addressbook_del_clicked), NULL);
1123 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1124 G_CALLBACK(addressbook_reg_clicked), NULL);
1125 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1126 G_CALLBACK(addressbook_lup_clicked), NULL);
1128 to_btn = gtk_button_new_with_label
1129 (prefs_common.trans_hdr ? _("To:") : "To:");
1130 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1131 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1132 cc_btn = gtk_button_new_with_label
1133 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
1134 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1135 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1136 bcc_btn = gtk_button_new_with_label
1137 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
1138 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1139 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1141 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1142 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1143 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1145 g_signal_connect(G_OBJECT(to_btn), "clicked",
1146 G_CALLBACK(addressbook_to_clicked),
1147 GINT_TO_POINTER(COMPOSE_TO));
1148 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1149 G_CALLBACK(addressbook_to_clicked),
1150 GINT_TO_POINTER(COMPOSE_CC));
1151 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1152 G_CALLBACK(addressbook_to_clicked),
1153 GINT_TO_POINTER(COMPOSE_BCC));
1154 g_signal_connect(G_OBJECT(close_btn), "clicked",
1155 G_CALLBACK(addressbook_close_clicked), NULL);
1157 /* Build icons for interface */
1158 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1159 &interfacexpm, &interfacexpmmask );
1161 /* Build control tables */
1162 addrbookctl_build_map(window);
1163 addrbookctl_build_iflist();
1164 addrbookctl_build_ifselect();
1166 addrbook.clist = NULL;
1168 /* Add each interface into the tree as a root level folder */
1169 nodeIf = _addressInterfaceList_;
1171 AdapterInterface *adapter = nodeIf->data;
1172 AddressInterface *iface = adapter->interface;
1173 nodeIf = g_list_next(nodeIf);
1175 if(iface->useInterface) {
1176 AddressTypeControlItem *atci = adapter->atci;
1177 text = atci->displayName;
1179 gtk_sctree_insert_node( GTK_CTREE(ctree),
1180 NULL, NULL, &text, FOLDER_SPACING,
1181 interfacexpm, interfacexpmmask,
1182 interfacexpm, interfacexpmmask,
1184 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1185 gtk_ctree_node_set_row_data_full(
1186 GTK_CTREE(ctree), adapter->treeNode, adapter,
1187 addressbook_free_treenode );
1192 n_entries = sizeof(addressbook_tree_popup_entries) /
1193 sizeof(addressbook_tree_popup_entries[0]);
1194 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1196 "<AddressBookTree>", &tree_factory,
1198 n_entries = sizeof(addressbook_list_popup_entries) /
1199 sizeof(addressbook_list_popup_entries[0]);
1200 list_popup = menu_create_items(addressbook_list_popup_entries,
1202 "<AddressBookList>", &list_factory,
1205 addrbook.window = window;
1206 addrbook.hpaned = hpaned;
1207 addrbook.vpaned = vpaned;
1208 addrbook.menubar = menubar;
1209 addrbook.ctree = ctree;
1212 addrbook.editaddress_vbox = editaddress_vbox;
1213 addrbook.clist = clist;
1214 addrbook.label = label;
1215 addrbook.entry = entry;
1216 addrbook.statusbar = statusbar;
1217 addrbook.status_cid = gtk_statusbar_get_context_id(
1218 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1220 addrbook.help_btn = help_btn;
1221 addrbook.edit_btn = edit_btn;
1222 addrbook.del_btn = del_btn;
1223 addrbook.reg_btn = reg_btn;
1224 addrbook.lup_btn = lup_btn;
1225 addrbook.to_btn = to_btn;
1226 addrbook.cc_btn = cc_btn;
1227 addrbook.bcc_btn = bcc_btn;
1229 addrbook.tree_popup = tree_popup;
1230 addrbook.list_popup = list_popup;
1231 addrbook.tree_factory = tree_factory;
1232 addrbook.list_factory = list_factory;
1233 addrbook.menu_factory = menu_factory;
1235 addrbook.listSelected = NULL;
1237 if (!geometry.min_height) {
1238 geometry.min_width = ADDRESSBOOK_WIDTH;
1239 geometry.min_height = ADDRESSBOOK_HEIGHT;
1242 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1244 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1245 prefs_common.addressbookwin_height);
1247 if (!prefs_common.addressbook_use_editaddress_dialog) {
1248 if (prefs_common.addressbook_vpaned_pos > 0)
1249 gtk_paned_set_position(GTK_PANED(vpaned),
1250 prefs_common.addressbook_vpaned_pos);
1252 if (prefs_common.addressbook_hpaned_pos > 0)
1253 gtk_paned_set_position(GTK_PANED(hpaned),
1254 prefs_common.addressbook_hpaned_pos);
1257 gtk_widget_show_all(window);
1261 * Close address book window and save to file(s).
1263 static gint addressbook_close( void ) {
1264 address_completion_end(addrbook.window);
1265 if (!prefs_common.addressbook_use_editaddress_dialog)
1266 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1268 addressbook_pane_save_position();
1270 gtk_widget_hide(addrbook.window);
1271 addressbook_export_to_file();
1276 * Display message in status line.
1277 * \param msg Message to display.
1279 static void addressbook_status_show( gchar *msg ) {
1280 if( addrbook.statusbar != NULL ) {
1282 GTK_STATUSBAR(addrbook.statusbar),
1283 addrbook.status_cid );
1286 GTK_STATUSBAR(addrbook.statusbar),
1287 addrbook.status_cid, msg );
1292 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1293 *addressbook_msgbuf = '\0';
1297 name = addrindex_ds_get_name( ds );
1298 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1299 "%s: %s", name, msg );
1302 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1305 addressbook_status_show( addressbook_msgbuf );
1308 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1312 *addressbook_msgbuf = '\0';
1314 name = addrindex_ds_get_name( ds );
1315 retVal = addrindex_ds_get_status_code( ds );
1316 if( retVal == MGU_SUCCESS ) {
1317 g_snprintf( addressbook_msgbuf,
1318 sizeof(addressbook_msgbuf), "%s", name );
1321 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1322 g_snprintf( addressbook_msgbuf,
1323 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1326 addressbook_status_show( addressbook_msgbuf );
1329 static void addressbook_button_set_sensitive(void)
1331 gboolean to_sens = FALSE;
1332 gboolean cc_sens = FALSE;
1333 gboolean bcc_sens = FALSE;
1335 if (!addrbook.window) return;
1337 if (addrbook.target_compose) {
1343 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1344 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1345 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1348 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1350 addressbook_edit_address_cb(NULL, 0, NULL);
1354 * Delete one or more objects from address list.
1356 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1358 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1359 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1360 AddressObject *pobj;
1361 AdapterDSource *ads = NULL;
1362 GtkCTreeNode *nodeList;
1365 AddressBookFile *abf = NULL;
1366 AddressDataSource *ds = NULL;
1367 AddressInterface *iface;
1368 AddrItemObject *aio;
1369 AddrSelectItem *item;
1371 gboolean refreshList = FALSE;
1373 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1374 g_return_if_fail(pobj != NULL);
1376 /* Test whether anything selected for deletion */
1377 nodeList = addrbook.listSelected;
1379 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1380 if( aio == NULL) return;
1381 ds = addressbook_find_datasource( addrbook.treeSelected );
1382 if( ds == NULL ) return;
1384 /* Test for read only */
1385 iface = ds->interface;
1386 if( iface->readOnly ) {
1387 alertpanel( _("Delete address(es)"),
1388 _("This address data is readonly and cannot be deleted."),
1389 GTK_STOCK_CLOSE, NULL, NULL );
1393 /* Test whether Ok to proceed */
1395 if( pobj->type == ADDR_DATASOURCE ) {
1396 ads = ADAPTER_DSOURCE(pobj);
1397 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1399 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1402 else if( pobj->type == ADDR_ITEM_GROUP ) {
1405 if( ! procFlag ) return;
1406 abf = ds->rawDataSource;
1407 if( abf == NULL ) return;
1410 /* Process deletions */
1411 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1412 gboolean group_delete = TRUE;
1413 /* Items inside folders */
1414 list = addrselect_get_list( _addressSelect_ );
1415 /* Confirm deletion */
1419 node = g_list_next( node );
1420 aio = ( AddrItemObject * ) item->addressItem;
1421 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1422 group_delete = FALSE;
1427 aval = alertpanel( _("Delete group"),
1428 _("Really delete the group(s)?\n"
1429 "The addresses it contains will not be lost."),
1430 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1431 if( aval != G_ALERTALTERNATE ) return;
1433 aval = alertpanel( _("Delete address(es)"),
1434 _("Really delete the address(es)?"),
1435 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1436 if( aval != G_ALERTALTERNATE ) return;
1442 node = g_list_next( node );
1443 aio = ( AddrItemObject * ) item->addressItem;
1444 if( aio->type == ADDR_ITEM_GROUP ) {
1445 ItemGroup *item = ( ItemGroup * ) aio;
1446 GtkCTreeNode *nd = NULL;
1448 nd = addressbook_find_group_node( addrbook.opened, item );
1449 item = addrbook_remove_group( abf, item );
1451 addritem_free_item_group( item );
1453 /* Remove group from parent node */
1454 gtk_ctree_remove_node( ctree, nd );
1457 else if( aio->type == ADDR_ITEM_PERSON ) {
1458 ItemPerson *item = ( ItemPerson * ) aio;
1459 addressbook_folder_remove_one_person( clist, item );
1460 if (pobj->type == ADDR_ITEM_FOLDER)
1461 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1462 item = addrbook_remove_person( abf, item );
1464 addritem_free_item_person( item );
1467 else if( aio->type == ADDR_ITEM_EMAIL ) {
1468 ItemEMail *item = ( ItemEMail * ) aio;
1469 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1470 item = addrbook_person_remove_email( abf, person, item );
1472 addrcache_remove_email(abf->addressCache, item);
1473 addritem_free_item_email( item );
1475 addressbook_folder_refresh_one_person( clist, person );
1478 g_list_free( list );
1479 addressbook_list_select_clear();
1481 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1482 addressbook_set_clist(
1483 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1487 addrbook_set_dirty(abf, TRUE);
1488 addressbook_export_to_file();
1489 addressbook_list_menu_setup();
1492 else if( pobj->type == ADDR_ITEM_GROUP ) {
1493 /* Items inside groups */
1494 list = addrselect_get_list( _addressSelect_ );
1498 node = g_list_next( node );
1499 aio = ( AddrItemObject * ) item->addressItem;
1500 if( aio->type == ADDR_ITEM_EMAIL ) {
1501 ItemEMail *item = ( ItemEMail * ) aio;
1502 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1503 item = addrbook_person_remove_email( abf, person, item );
1505 addritem_free_item_email( item );
1509 g_list_free( list );
1510 addressbook_list_select_clear();
1511 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1512 addressbook_set_clist(
1513 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1517 addrbook_set_dirty(abf, TRUE);
1518 addressbook_export_to_file();
1519 addressbook_list_menu_setup();
1523 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1524 gtk_ctree_remove_node( clist, nodeList );
1528 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1530 addressbook_new_address_cb( NULL, 0, NULL );
1533 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1536 gchar *address = NULL;
1538 if( aio->type == ADDR_ITEM_EMAIL ) {
1539 ItemPerson *person = NULL;
1540 ItemEMail *email = ( ItemEMail * ) aio;
1542 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1543 if( email->address ) {
1544 if( ADDRITEM_NAME(email) ) {
1545 name = ADDRITEM_NAME(email);
1546 if( *name == '\0' ) {
1547 name = ADDRITEM_NAME(person);
1550 else if( ADDRITEM_NAME(person) ) {
1551 name = ADDRITEM_NAME(person);
1554 buf = g_strdup( email->address );
1556 address = email->address;
1559 else if( aio->type == ADDR_ITEM_PERSON ) {
1560 ItemPerson *person = ( ItemPerson * ) aio;
1561 GList *node = person->listEMail;
1563 name = ADDRITEM_NAME(person);
1565 ItemEMail *email = ( ItemEMail * ) node->data;
1566 address = email->address;
1570 if( name && name[0] != '\0' ) {
1571 if( strchr_with_skip_quote( name, '"', ',' ) )
1572 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1574 buf = g_strdup_printf( "%s <%s>", name, address );
1577 buf = g_strdup( address );
1584 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1588 AddrSelectItem *item;
1589 AddrItemObject *aio;
1592 compose = addrbook.target_compose;
1593 if( ! compose ) return;
1595 /* Nothing selected, but maybe there is something in text entry */
1596 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1598 compose_entry_append(
1599 compose, addr, (ComposeEntryType)data );
1602 /* Select from address list */
1603 list = addrselect_get_list( _addressSelect_ );
1608 node = g_list_next( node );
1609 aio = item->addressItem;
1610 if( aio->type == ADDR_ITEM_PERSON ||
1611 aio->type == ADDR_ITEM_EMAIL ) {
1612 addr = addressbook_format_address( aio );
1613 compose_entry_append(
1614 compose, addr, (ComposeEntryType) data );
1617 else if( aio->type == ADDR_ITEM_GROUP ) {
1618 ItemGroup *group = ( ItemGroup * ) aio;
1619 GList *nodeMail = group->listEMail;
1621 ItemEMail *email = nodeMail->data;
1623 addr = addressbook_format_address(
1624 ( AddrItemObject * ) email );
1625 compose_entry_append(
1626 compose, addr, (ComposeEntryType) data );
1628 nodeMail = g_list_next( nodeMail );
1633 AddressObject *obj = NULL;
1635 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1637 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1638 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1639 GList *nodeMail = itemGroup->listEMail;
1641 ItemEMail *email = nodeMail->data;
1643 addr = addressbook_format_address(
1644 ( AddrItemObject * ) email );
1645 compose_entry_append(
1646 compose, addr, (ComposeEntryType) data );
1648 nodeMail = g_list_next( nodeMail );
1652 g_list_free( list );
1655 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1656 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1657 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1658 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1660 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1661 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1662 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1663 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1665 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1666 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1667 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1668 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1669 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1670 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1673 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1674 gboolean canEdit = FALSE;
1675 gboolean canDelete = TRUE;
1676 gboolean canAdd = FALSE;
1677 gboolean canEditTr = TRUE;
1678 gboolean editAddress = FALSE;
1679 gboolean canExport = TRUE;
1680 AddressTypeControlItem *atci = NULL;
1681 AddressDataSource *ds = NULL;
1682 AddressInterface *iface = NULL;
1684 if( obj == NULL ) return;
1685 if( obj->type == ADDR_INTERFACE ) {
1686 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1687 iface = adapter->interface;
1689 if( iface->haveLibrary ) {
1690 /* Enable appropriate File / New command */
1691 atci = adapter->atci;
1692 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1695 canEditTr = canExport = FALSE;
1697 else if( obj->type == ADDR_DATASOURCE ) {
1698 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1699 ds = ads->dataSource;
1700 iface = ds->interface;
1701 if( ! iface->readOnly ) {
1702 canAdd = canEdit = editAddress = canDelete = TRUE;
1704 if( ! iface->haveLibrary ) {
1705 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1708 else if( obj->type == ADDR_ITEM_FOLDER ) {
1709 ds = addressbook_find_datasource( addrbook.treeSelected );
1711 iface = ds->interface;
1712 if( iface->readOnly ) {
1717 canAdd = editAddress = TRUE;
1721 else if( obj->type == ADDR_ITEM_GROUP ) {
1722 ds = addressbook_find_datasource( addrbook.treeSelected );
1724 iface = ds->interface;
1725 if( ! iface->readOnly ) {
1731 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1734 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1735 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1736 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1737 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1740 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1741 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1742 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1743 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1745 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1746 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1749 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1750 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1753 static void addressbook_list_menu_setup( void );
1756 * Address book tree callback function that responds to selection of tree
1759 * \param ctree Tree widget.
1760 * \param node Node that was selected.
1761 * \param column Column number where selected occurred.
1762 * \param data Pointer to user data.
1764 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1765 gint column, gpointer data)
1767 AddressObject *obj = NULL;
1768 AdapterDSource *ads = NULL;
1769 AddressDataSource *ds = NULL;
1770 ItemFolder *rootFolder = NULL;
1771 AddressObjectType aot;
1773 addrbook.treeSelected = node;
1774 addrbook.listSelected = NULL;
1775 addressbook_status_show( "" );
1776 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1778 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1780 addressbook_set_clist(NULL, TRUE);
1783 addrbook.opened = node;
1785 if( obj->type == ADDR_DATASOURCE ) {
1786 /* Read from file */
1787 static gboolean tVal = TRUE;
1789 ads = ADAPTER_DSOURCE(obj);
1790 if( ads == NULL ) return;
1791 ds = ads->dataSource;
1792 if( ds == NULL ) return;
1794 if( addrindex_ds_get_modify_flag( ds ) ) {
1795 addrindex_ds_read_data( ds );
1798 if( ! addrindex_ds_get_read_flag( ds ) ) {
1799 addrindex_ds_read_data( ds );
1801 addressbook_ds_show_message( ds );
1803 if( ! addrindex_ds_get_access_flag( ds ) ) {
1804 /* Remove existing folders and groups */
1805 gtk_clist_freeze( GTK_CLIST(ctree) );
1806 addressbook_tree_remove_children( ctree, node );
1807 gtk_clist_thaw( GTK_CLIST(ctree) );
1809 /* Load folders into the tree */
1810 rootFolder = addrindex_ds_get_root_folder( ds );
1811 if( ds->type == ADDR_IF_JPILOT ) {
1812 aot = ADDR_CATEGORY;
1814 else if( ds->type == ADDR_IF_LDAP ) {
1815 aot = ADDR_LDAP_QUERY;
1818 aot = ADDR_ITEM_FOLDER;
1820 addressbook_node_add_folder( node, ds, rootFolder, aot );
1821 addrindex_ds_set_access_flag( ds, &tVal );
1822 gtk_ctree_expand( ctree, node );
1825 addressbook_set_clist(NULL, TRUE);
1828 /* Update address list */
1829 g_signal_handlers_block_by_func
1831 G_CALLBACK(addressbook_tree_selected), NULL);
1832 addressbook_set_clist( obj, FALSE );
1833 g_signal_handlers_unblock_by_func
1835 G_CALLBACK(addressbook_tree_selected), NULL);
1836 if (!prefs_common.addressbook_use_editaddress_dialog)
1837 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1839 /* Setup main menu selections */
1840 addressbook_menubar_set_sensitive( FALSE );
1841 addressbook_list_menu_setup();
1842 addressbook_menuitem_set_sensitive( obj, node );
1844 addressbook_list_select_clear();
1845 addressbook_list_menu_setup();
1850 * Setup address list popup menu items. Items are enabled or disabled as
1853 static void addressbook_list_menu_setup( void ) {
1854 GtkCTree *clist = NULL;
1855 AddressObject *pobj = NULL;
1856 AddressObject *obj = NULL;
1857 AdapterDSource *ads = NULL;
1858 AddressInterface *iface = NULL;
1859 AddressDataSource *ds = NULL;
1860 gboolean canEdit = FALSE;
1861 gboolean canDelete = FALSE;
1862 gboolean canCut = FALSE;
1863 gboolean canCopy = FALSE;
1864 gboolean canPaste = FALSE;
1865 gboolean canBrowse = FALSE;
1867 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1868 if( pobj == NULL ) return;
1870 clist = GTK_CTREE(addrbook.clist);
1871 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1872 if( obj == NULL ) canEdit = FALSE;
1874 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1875 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1877 if( pobj->type == ADDR_DATASOURCE ) {
1878 /* Parent object is a data source */
1879 ads = ADAPTER_DSOURCE(pobj);
1880 ds = ads->dataSource;
1881 iface = ds->interface;
1882 if( ! iface->readOnly ) {
1883 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1884 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1885 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1886 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1887 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1888 if( obj ) canEdit = TRUE;
1890 canDelete = canEdit;
1892 else if( pobj->type != ADDR_INTERFACE ) {
1893 /* Parent object is not an interface */
1894 ds = addressbook_find_datasource( addrbook.treeSelected );
1895 iface = ds->interface;
1896 if( ! iface->readOnly ) {
1897 /* Folder or group */
1898 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1899 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1900 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1901 if( obj ) canEdit = TRUE;
1904 if( pobj->type == ADDR_ITEM_FOLDER ) {
1905 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1906 if( obj ) canEdit = TRUE;
1908 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1909 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1910 canDelete = canEdit;
1912 if( iface->type == ADDR_IF_LDAP ) {
1913 if( obj ) canBrowse = TRUE;
1918 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1920 /* Disable edit or browse if more than one row selected */
1921 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1926 /* Now go finalize menu items */
1927 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1928 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1930 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1931 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1932 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1933 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1935 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1937 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1938 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1939 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1940 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1942 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1943 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1944 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1946 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1947 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1948 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1950 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1951 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1954 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1958 static void addressbook_select_row_tree (GtkCTree *ctree,
1966 * Add list of items into tree node below specified tree node.
1967 * \param treeNode Tree node.
1968 * \param ds Data source.
1969 * \param listItems List of items.
1971 static void addressbook_treenode_add_list(
1972 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1978 AddrItemObject *aio;
1982 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
1985 group = ( ItemGroup * ) aio;
1986 nn = addressbook_node_add_group( treeNode, ds, group );
1988 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
1991 folder = ( ItemFolder * ) aio;
1992 nn = addressbook_node_add_folder(
1993 treeNode, ds, folder, ADDR_ITEM_FOLDER );
1995 node = g_list_next( node );
1999 static void addressbook_select_all_cb( void ) {
2000 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2004 * Cut from address list widget.
2006 static void addressbook_clip_cut_cb( void ) {
2007 _clipBoard_->cutFlag = TRUE;
2008 addrclip_clear( _clipBoard_ );
2009 addrclip_add( _clipBoard_, _addressSelect_ );
2010 /* addrclip_list_show( _clipBoard_, stdout ); */
2014 * Copy from address list widget.
2016 static void addressbook_clip_copy_cb( void ) {
2017 _clipBoard_->cutFlag = FALSE;
2018 addrclip_clear( _clipBoard_ );
2019 addrclip_add( _clipBoard_, _addressSelect_ );
2020 /* addrclip_list_show( _clipBoard_, stdout ); */
2024 * Paste clipboard into address list widget.
2026 static void addressbook_clip_paste_cb( void ) {
2027 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2028 AddressObject *pobj = NULL;
2029 AddressDataSource *ds = NULL;
2030 AddressBookFile *abf = NULL;
2031 ItemFolder *folder = NULL;
2032 GList *folderGroup = NULL;
2034 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2035 if( ds == NULL ) return;
2036 if( addrindex_ds_get_readonly( ds ) ) {
2037 addressbook_ds_status_message(
2038 ds, _( "Cannot paste. Target address book is readonly." ) );
2042 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2044 if( pobj->type == ADDR_ITEM_FOLDER ) {
2045 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2047 else if( pobj->type == ADDR_ITEM_GROUP ) {
2048 addressbook_ds_status_message(
2049 ds, _( "Cannot paste into an address group." ) );
2054 /* Get an address book */
2055 abf = addressbook_get_book_file();
2056 if( abf == NULL ) return;
2058 if( _clipBoard_->cutFlag ) {
2060 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2062 /* Remove all groups and folders in clipboard from tree node */
2063 addressbook_treenode_remove_item();
2065 /* Remove all "cut" items */
2066 addrclip_delete_item( _clipBoard_ );
2068 /* Clear clipboard - cut items??? */
2069 addrclip_clear( _clipBoard_ );
2073 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2076 /* addrclip_list_show( _clipBoard_, stdout ); */
2078 /* Update tree by inserting node for each folder or group */
2079 addressbook_treenode_add_list(
2080 addrbook.treeSelected, ds, folderGroup );
2081 gtk_ctree_expand( ctree, addrbook.treeSelected );
2082 g_list_free( folderGroup );
2086 /* Display items pasted */
2087 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2088 addressbook_set_clist(
2089 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2097 * Add current treenode object to clipboard. Note that widget only allows
2098 * one entry from the tree list to be selected.
2100 static void addressbook_treenode_to_clipboard( void ) {
2101 AddressObject *obj = NULL;
2102 AddressDataSource *ds = NULL;
2103 AddrSelectItem *item;
2104 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2107 node = addrbook.treeSelected;
2108 if( node == NULL ) return;
2109 obj = gtk_ctree_node_get_row_data( ctree, node );
2110 if( obj == NULL ) return;
2112 ds = addressbook_find_datasource( node );
2113 if( ds == NULL ) return;
2116 if( obj->type == ADDR_ITEM_FOLDER ) {
2117 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2118 ItemFolder *folder = adapter->itemFolder;
2120 item = addrselect_create_node( obj );
2121 item->uid = g_strdup( ADDRITEM_ID(folder) );
2123 else if( obj->type == ADDR_ITEM_GROUP ) {
2124 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2125 ItemGroup *group = adapter->itemGroup;
2127 item = addrselect_create_node( obj );
2128 item->uid = g_strdup( ADDRITEM_ID(group) );
2130 else if( obj->type == ADDR_DATASOURCE ) {
2132 item = addrselect_create_node( obj );
2137 /* Clear existing list and add item into list */
2140 addressbook_list_select_clear();
2141 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2142 addrselect_list_add( _addressSelect_, item, cacheID );
2148 * Cut from tree widget.
2150 static void addressbook_treenode_cut_cb( void ) {
2151 _clipBoard_->cutFlag = TRUE;
2152 addressbook_treenode_to_clipboard();
2153 addrclip_clear( _clipBoard_ );
2154 addrclip_add( _clipBoard_, _addressSelect_ );
2155 /* addrclip_list_show( _clipBoard_, stdout ); */
2159 * Copy from tree widget.
2161 static void addressbook_treenode_copy_cb( void ) {
2162 _clipBoard_->cutFlag = FALSE;
2163 addressbook_treenode_to_clipboard();
2164 addrclip_clear( _clipBoard_ );
2165 addrclip_add( _clipBoard_, _addressSelect_ );
2166 /* addrclip_list_show( _clipBoard_, stdout ); */
2170 * Paste clipboard into address tree widget.
2172 static void addressbook_treenode_paste_cb( void ) {
2173 addressbook_clip_paste_cb();
2177 * Clear selected entries in clipboard.
2179 static void addressbook_list_select_clear( void ) {
2180 addrselect_list_clear( _addressSelect_ );
2184 * Add specified address item to selected address list.
2185 * \param aio Address item object.
2186 * \param ds Datasource.
2188 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2191 if( ds == NULL ) return;
2192 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2193 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2198 * Remove specified address item from selected address list.
2199 * \param aio Address item object.
2201 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2202 addrselect_list_remove( _addressSelect_, aio );
2206 * Invoke EMail compose window with addresses in selected address list.
2208 static void addressbook_mail_to_cb( void ) {
2211 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2212 listAddress = addrselect_build_list( _addressSelect_ );
2213 compose_new_with_list( NULL, listAddress );
2214 mgu_free_dlist( listAddress );
2219 static void addressbook_list_row_selected( GtkCTree *clist,
2224 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2225 AddrItemObject *aio = NULL;
2226 AddressObject *pobj = NULL;
2227 AdapterDSource *ads = NULL;
2228 AddressDataSource *ds = NULL;
2230 gtk_entry_set_text( entry, "" );
2231 addrbook.listSelected = node;
2233 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2234 if( pobj == NULL ) return;
2236 if( pobj->type == ADDR_DATASOURCE ) {
2237 ads = ADAPTER_DSOURCE(pobj);
2238 ds = ads->dataSource;
2240 else if( pobj->type != ADDR_INTERFACE ) {
2241 ds = addressbook_find_datasource( addrbook.treeSelected );
2244 aio = gtk_ctree_node_get_row_data( clist, node );
2246 /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
2247 addressbook_list_select_add( aio, ds );
2250 addressbook_list_menu_setup();
2252 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2253 addressbook_edit_address(NULL, 0, NULL, FALSE);
2256 static void addressbook_list_row_unselected( GtkCTree *ctree,
2261 AddrItemObject *aio;
2263 aio = gtk_ctree_node_get_row_data( ctree, node );
2265 /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2266 addressbook_list_select_remove( aio );
2269 if (!prefs_common.addressbook_use_editaddress_dialog)
2270 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2273 /* from gdkevents.c */
2274 #define DOUBLE_CLICK_TIME 250
2276 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2277 GdkEventButton *event,
2280 static guint32 lasttime = 0;
2281 if( ! event ) return FALSE;
2283 addressbook_list_menu_setup();
2285 if( event->button == 3 ) {
2286 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2287 event->button, event->time );
2288 } else if (event->button == 1) {
2289 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2290 if (prefs_common.add_address_by_click &&
2291 addrbook.target_compose)
2292 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2294 if (prefs_common.addressbook_use_editaddress_dialog)
2295 addressbook_edit_address_cb(NULL, 0, NULL);
2299 lasttime = event->time;
2305 static gboolean addressbook_list_button_released(GtkWidget *widget,
2306 GdkEventButton *event,
2312 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2313 GdkEventButton *event,
2316 GtkCList *clist = GTK_CLIST(ctree);
2318 AddressObject *obj = NULL;
2319 AdapterDSource *ads = NULL;
2320 AddressInterface *iface = NULL;
2321 AddressDataSource *ds = NULL;
2322 gboolean canEdit = FALSE;
2323 gboolean canDelete = FALSE;
2324 gboolean canCut = FALSE;
2325 gboolean canCopy = FALSE;
2326 gboolean canPaste = FALSE;
2327 gboolean canTreeCut = FALSE;
2328 gboolean canTreeCopy = FALSE;
2329 gboolean canTreePaste = FALSE;
2330 gboolean canLookup = FALSE;
2331 GtkCTreeNode *node = NULL;
2333 if( ! event ) return FALSE;
2334 addressbook_menubar_set_sensitive( FALSE );
2336 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2337 gtkut_clist_set_focus_row(clist, row);
2338 obj = gtk_clist_get_row_data( clist, row );
2341 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2343 if( obj == NULL ) return FALSE;
2344 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2346 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2347 canTreePaste = TRUE;
2350 if (obj->type == ADDR_INTERFACE) {
2351 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2352 iface = adapter->interface;
2355 canTreeCopy = FALSE;
2356 if( iface->readOnly ) {
2357 canTreePaste = FALSE;
2360 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2361 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2363 if( iface->externalQuery ) canLookup = TRUE;
2365 if (obj->type == ADDR_DATASOURCE) {
2366 ads = ADAPTER_DSOURCE(obj);
2367 ds = ads->dataSource;
2370 iface = ds->interface;
2375 if( iface->readOnly ) {
2376 canTreePaste = FALSE;
2379 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2380 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2381 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2384 if( iface->externalQuery ) canLookup = TRUE;
2386 else if (obj->type == ADDR_ITEM_FOLDER) {
2387 ds = addressbook_find_datasource( node );
2391 iface = ds->interface;
2394 if( iface->readOnly ) {
2395 canTreePaste = FALSE;
2401 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2402 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2403 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2407 if( iface->externalQuery ) {
2408 /* Enable deletion of LDAP folder */
2413 else if (obj->type == ADDR_ITEM_GROUP) {
2414 ds = addressbook_find_datasource( node );
2417 iface = ds->interface;
2420 if( ! iface->readOnly ) {
2423 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2424 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2427 else if (obj->type == ADDR_INTERFACE) {
2428 canTreePaste = FALSE;
2432 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2434 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2435 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2439 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2440 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2441 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2442 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2443 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2445 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2446 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2447 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2448 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2449 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2450 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2452 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2453 if( event->button == 3 ) {
2454 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2455 event->button, event->time);
2461 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2462 GdkEventButton *event,
2465 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2469 static void addressbook_new_folder_cb(gpointer data, guint action,
2472 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2473 AddressObject *obj = NULL;
2474 AddressDataSource *ds = NULL;
2475 AddressBookFile *abf = NULL;
2476 ItemFolder *parentFolder = NULL;
2477 ItemFolder *folder = NULL;
2479 if( ! addrbook.treeSelected ) return;
2480 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2481 if( obj == NULL ) return;
2482 ds = addressbook_find_datasource( addrbook.treeSelected );
2483 if( ds == NULL ) return;
2485 if( obj->type == ADDR_DATASOURCE ) {
2486 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2488 else if( obj->type == ADDR_ITEM_FOLDER ) {
2489 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2495 abf = ds->rawDataSource;
2496 if( abf == NULL ) return;
2497 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2500 nn = addressbook_node_add_folder(
2501 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2502 gtk_ctree_expand( ctree, addrbook.treeSelected );
2503 if( addrbook.treeSelected == addrbook.opened )
2504 addressbook_set_clist(obj, TRUE);
2509 static void addressbook_new_group_cb(gpointer data, guint action,
2512 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2513 AddressObject *obj = NULL;
2514 AddressDataSource *ds = NULL;
2515 AddressBookFile *abf = NULL;
2516 ItemFolder *parentFolder = NULL;
2517 ItemGroup *group = NULL;
2519 if( ! addrbook.treeSelected ) return;
2520 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2521 if( obj == NULL ) return;
2522 ds = addressbook_find_datasource( addrbook.treeSelected );
2523 if( ds == NULL ) return;
2525 if( obj->type == ADDR_DATASOURCE ) {
2526 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2528 else if( obj->type == ADDR_ITEM_FOLDER ) {
2529 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2535 abf = ds->rawDataSource;
2536 if( abf == NULL ) return;
2537 group = addressbook_edit_group( abf, parentFolder, NULL );
2540 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2541 gtk_ctree_expand( ctree, addrbook.treeSelected );
2542 if( addrbook.treeSelected == addrbook.opened )
2543 addressbook_set_clist(obj, TRUE);
2548 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2550 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2553 GdkPixmap *pix_cl, *pix_op;
2554 GdkBitmap *mask_cl, *mask_op;
2555 gboolean is_leaf, expanded;
2557 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2558 &pix_cl, &mask_cl, &pix_op, &mask_op,
2559 &is_leaf, &expanded);
2560 gtk_sctree_set_node_info(ctree, node, name, spacing,
2561 pix_cl, mask_cl, pix_op, mask_op,
2567 * \param obj Address object to edit.
2568 * \param node Node in tree.
2569 * \return New name of data source.
2571 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2572 gchar *newName = NULL;
2573 AddressDataSource *ds = NULL;
2574 AddressInterface *iface = NULL;
2575 AdapterDSource *ads = NULL;
2577 ds = addressbook_find_datasource( node );
2578 if( ds == NULL ) return NULL;
2579 iface = ds->interface;
2580 if( ! iface->haveLibrary ) return NULL;
2582 /* Read data from data source */
2583 if( addrindex_ds_get_modify_flag( ds ) ) {
2584 addrindex_ds_read_data( ds );
2587 if( ! addrindex_ds_get_read_flag( ds ) ) {
2588 addrindex_ds_read_data( ds );
2592 ads = ADAPTER_DSOURCE(obj);
2593 if( ads->subType == ADDR_BOOK ) {
2594 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2596 else if( ads->subType == ADDR_VCARD ) {
2597 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2600 else if( ads->subType == ADDR_JPILOT ) {
2601 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2605 else if( ads->subType == ADDR_LDAP ) {
2606 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2612 newName = obj->name;
2617 * Edit an object that is in the address tree area.
2619 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2622 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2624 AddressDataSource *ds = NULL;
2625 AddressBookFile *abf = NULL;
2626 GtkCTreeNode *node = NULL, *parentNode = NULL;
2629 if( ! addrbook.treeSelected ) return;
2630 node = addrbook.treeSelected;
2631 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2632 obj = gtk_ctree_node_get_row_data( ctree, node );
2633 if( obj == NULL ) return;
2634 parentNode = GTK_CTREE_ROW(node)->parent;
2636 ds = addressbook_find_datasource( node );
2637 if( ds == NULL ) return;
2639 if( obj->type == ADDR_DATASOURCE ) {
2640 name = addressbook_edit_datasource( obj, node );
2641 if( name == NULL ) return;
2644 abf = ds->rawDataSource;
2645 if( abf == NULL ) return;
2646 if( obj->type == ADDR_ITEM_FOLDER ) {
2647 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2648 ItemFolder *item = adapter->itemFolder;
2649 ItemFolder *parentFolder = NULL;
2650 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2651 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2652 name = ADDRITEM_NAME(item);
2654 else if( obj->type == ADDR_ITEM_GROUP ) {
2655 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2656 ItemGroup *item = adapter->itemGroup;
2657 ItemFolder *parentFolder = NULL;
2658 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2659 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2660 name = ADDRITEM_NAME(item);
2663 if( name && parentNode ) {
2664 /* Update node in tree view */
2665 addressbook_change_node_name( node, name );
2666 gtk_sctree_sort_node(ctree, parentNode);
2667 gtk_ctree_expand( ctree, node );
2668 gtk_sctree_select( GTK_SCTREE( ctree), node );
2675 ADDRTREE_DEL_FOLDER_ONLY,
2676 ADDRTREE_DEL_FOLDER_ADDR
2680 * Delete an item from the tree widget.
2681 * \param data Data passed in.
2682 * \param action Action.
2683 * \param widget Widget issuing callback.
2685 static void addressbook_treenode_delete_cb(
2686 gpointer data, guint action, GtkWidget *widget )
2688 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2689 GtkCTreeNode *node = NULL;
2693 AddrBookBase *adbase;
2694 AddressCache *cache;
2695 AdapterDSource *ads = NULL;
2696 AddressInterface *iface = NULL;
2697 AddressDataSource *ds = NULL;
2698 gboolean remFlag = FALSE;
2699 TreeItemDelType delType;
2701 if( ! addrbook.treeSelected ) return;
2702 node = addrbook.treeSelected;
2703 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2705 obj = gtk_ctree_node_get_row_data( ctree, node );
2706 g_return_if_fail(obj != NULL);
2708 if( obj->type == ADDR_DATASOURCE ) {
2709 ads = ADAPTER_DSOURCE(obj);
2710 if( ads == NULL ) return;
2711 ds = ads->dataSource;
2712 if( ds == NULL ) return;
2715 /* Must be folder or something else */
2716 ds = addressbook_find_datasource( node );
2717 if( ds == NULL ) return;
2719 /* Only allow deletion from non-readOnly */
2720 iface = ds->interface;
2721 if( iface->readOnly ) {
2722 /* Allow deletion of query results */
2723 if( ! iface->externalQuery ) return;
2727 /* Confirm deletion */
2728 delType = ADDRTREE_DEL_NONE;
2729 if( obj->type == ADDR_ITEM_FOLDER ) {
2730 if( iface->externalQuery ) {
2731 message = g_strdup_printf( _(
2732 "Do you want to delete the query " \
2733 "results and addresses in '%s' ?" ),
2735 aval = alertpanel( _("Delete"), message,
2736 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2738 if( aval == G_ALERTALTERNATE ) {
2739 delType = ADDRTREE_DEL_FOLDER_ADDR;
2743 message = g_strdup_printf
2744 ( _( "Do you want to delete '%s' ?"
2745 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2747 aval = alertpanel( _("Delete folder"), message,
2748 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2750 if( aval == G_ALERTALTERNATE ) {
2751 delType = ADDRTREE_DEL_FOLDER_ONLY;
2753 else if( aval == G_ALERTOTHER ) {
2754 delType = ADDRTREE_DEL_FOLDER_ADDR;
2758 else if( obj->type == ADDR_ITEM_GROUP ) {
2759 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2760 "The addresses it contains will not be lost."), obj->name);
2761 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2762 "+" GTK_STOCK_DELETE, NULL);
2764 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2766 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2767 "The addresses it contains will be lost."), obj->name);
2768 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2769 "+" GTK_STOCK_DELETE, NULL);
2771 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2773 if( delType == ADDRTREE_DEL_NONE ) return;
2775 /* Proceed with deletion */
2776 if( obj->type == ADDR_DATASOURCE ) {
2777 /* Remove node from tree */
2778 gtk_ctree_remove_node( ctree, node );
2780 /* Remove data source. */
2781 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2782 addrindex_free_datasource( ds );
2787 /* Get reference to cache */
2788 adbase = ( AddrBookBase * ) ds->rawDataSource;
2789 if( adbase == NULL ) return;
2790 cache = adbase->addressCache;
2792 /* Remove query results folder */
2793 if( iface->externalQuery ) {
2794 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2795 ItemFolder *folder = adapter->itemFolder;
2797 adapter->itemFolder = NULL;
2799 printf( "remove folder for ::%s::\n", obj->name );
2800 printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2801 printf( "-------------- remove results\n" );
2803 addrindex_remove_results( ds, folder );
2804 /* printf( "-------------- remove node\n" ); */
2805 gtk_ctree_remove_node( ctree, node );
2809 /* Code below is valid for regular address book deletion */
2810 if( obj->type == ADDR_ITEM_FOLDER ) {
2811 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2812 ItemFolder *item = adapter->itemFolder;
2814 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2815 /* Remove folder only */
2816 item = addrcache_remove_folder( cache, item );
2818 addritem_free_item_folder( item );
2819 addressbook_move_nodes_up( ctree, node );
2823 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2824 /* Remove folder and addresses */
2825 item = addrcache_remove_folder_delete( cache, item );
2827 addritem_free_item_folder( item );
2832 else if( obj->type == ADDR_ITEM_GROUP ) {
2833 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2834 ItemGroup *item = adapter->itemGroup;
2836 item = addrcache_remove_group( cache, item );
2838 addritem_free_item_group( item );
2845 gtk_ctree_remove_node(ctree, node );
2849 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2851 if( person && addrbook.treeSelected == addrbook.opened ) {
2852 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2853 addressbook_folder_refresh_one_person(
2854 GTK_CTREE(addrbook.clist), person );
2856 addressbook_address_list_set_focus();
2859 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2861 if( person && addrbook.treeSelected == addrbook.opened) {
2862 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2863 addressbook_set_clist(
2864 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2868 addressbook_address_list_set_focus();
2871 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2872 AddressObject *pobj = NULL;
2873 AddressDataSource *ds = NULL;
2874 AddressBookFile *abf = NULL;
2876 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2877 if( pobj == NULL ) return;
2878 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2879 if( ds == NULL ) return;
2881 abf = ds->rawDataSource;
2882 if( abf == NULL ) return;
2884 if( pobj->type == ADDR_DATASOURCE ) {
2885 if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) {
2887 ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE,
2888 addrbook.editaddress_vbox,
2889 addressbook_new_address_from_book_post_cb,
2891 if (prefs_common.addressbook_use_editaddress_dialog)
2892 addressbook_new_address_from_book_post_cb( person );
2895 else if( pobj->type == ADDR_ITEM_FOLDER ) {
2897 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
2898 ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE,
2899 addrbook.editaddress_vbox,
2900 addressbook_new_address_from_folder_post_cb,
2902 if (prefs_common.addressbook_use_editaddress_dialog)
2903 addressbook_new_address_from_folder_post_cb( person );
2905 else if( pobj->type == ADDR_ITEM_GROUP ) {
2906 /* New address in group */
2907 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
2908 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
2909 if (addrbook.treeSelected == addrbook.opened) {
2910 /* Change node name in tree. */
2911 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
2912 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2913 addressbook_set_clist(
2914 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2922 * Search for specified child group node in address index tree.
2923 * \param parent Parent node.
2924 * \param group Group to find.
2926 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
2927 GtkCTreeNode *node = NULL;
2928 GtkCTreeRow *currRow;
2930 currRow = GTK_CTREE_ROW( parent );
2932 node = currRow->children;
2936 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2937 if( obj->type == ADDR_ITEM_GROUP ) {
2938 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
2939 if( g == group ) return node;
2941 currRow = GTK_CTREE_ROW(node);
2942 node = currRow->sibling;
2948 static AddressBookFile *addressbook_get_book_file() {
2949 AddressBookFile *abf = NULL;
2950 AddressDataSource *ds = NULL;
2952 ds = addressbook_find_datasource( addrbook.treeSelected );
2953 if( ds == NULL ) return NULL;
2954 if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
2958 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
2962 /* Remove existing folders and groups */
2963 row = GTK_CTREE_ROW( parent );
2965 while( (node = row->children) ) {
2966 gtk_ctree_remove_node( ctree, node );
2971 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
2972 GtkCTreeNode *parent, *child;
2973 GtkCTreeRow *currRow;
2974 currRow = GTK_CTREE_ROW( node );
2976 parent = currRow->parent;
2977 while( (child = currRow->children) ) {
2978 gtk_ctree_move( ctree, child, parent, node );
2980 gtk_sctree_sort_node( ctree, parent );
2984 static void addressbook_edit_address_post_cb( ItemPerson *person )
2987 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
2988 invalidate_address_completion();
2990 addressbook_address_list_set_focus();
2993 void addressbook_address_list_set_focus( void )
2995 if (!prefs_common.addressbook_use_editaddress_dialog) {
2996 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
2997 addressbook_list_menu_setup();
3001 void addressbook_address_list_disable_some_actions(void)
3003 /* disable address copy/pasting when editing contact's detail (embedded form) */
3004 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3005 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3006 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3008 /* we're already editing contact's detail here */
3009 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3010 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3013 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3014 addressbook_edit_address(data, action, widget, TRUE);
3017 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3018 gboolean force_focus ) {
3019 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3021 AddressObject *obj = NULL, *pobj = NULL;
3022 AddressDataSource *ds = NULL;
3023 GtkCTreeNode *node = NULL, *parentNode = NULL;
3025 AddressBookFile *abf = NULL;
3027 if( addrbook.listSelected == NULL ) return;
3028 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3029 g_return_if_fail(obj != NULL);
3031 ctree = GTK_CTREE( addrbook.ctree );
3032 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3033 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3035 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3036 if( ds == NULL ) return;
3038 abf = addressbook_get_book_file();
3040 if( obj->type == ADDR_ITEM_EMAIL ) {
3041 ItemEMail *email = ( ItemEMail * ) obj;
3042 if( email == NULL ) return;
3043 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3044 /* Edit parent group */
3045 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3046 ItemGroup *itemGrp = adapter->itemGroup;
3047 if( abf == NULL ) return;
3048 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3049 name = ADDRITEM_NAME(itemGrp);
3050 node = addrbook.treeSelected;
3051 parentNode = GTK_CTREE_ROW(node)->parent;
3054 /* Edit person - email page */
3056 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3057 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3058 addressbook_edit_address_post_cb,
3059 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3061 if (prefs_common.addressbook_use_editaddress_dialog)
3062 addressbook_edit_address_post_cb( person );
3067 else if( obj->type == ADDR_ITEM_PERSON ) {
3068 /* Edit person - basic page */
3069 ItemPerson *person = ( ItemPerson * ) obj;
3070 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3071 addressbook_edit_address_post_cb,
3072 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3074 if (prefs_common.addressbook_use_editaddress_dialog)
3075 addressbook_edit_address_post_cb( person );
3079 else if( obj->type == ADDR_ITEM_GROUP ) {
3080 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3081 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3082 parentNode = addrbook.treeSelected;
3083 node = addressbook_find_group_node( parentNode, itemGrp );
3084 name = ADDRITEM_NAME(itemGrp);
3085 invalidate_address_completion();
3091 /* Update tree node with node name */
3092 if( node == NULL ) return;
3093 addressbook_change_node_name( node, name );
3094 gtk_sctree_sort_node( ctree, parentNode );
3095 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3096 addressbook_set_clist(
3097 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3102 static void addressbook_delete_address_cb(gpointer data, guint action,
3105 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3106 addressbook_del_clicked(NULL, NULL);
3107 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3110 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3112 addressbook_close();
3115 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3116 addressbook_export_to_file();
3119 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3121 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3122 if( person ) addritem_person_set_opened( person, TRUE );
3126 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3128 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3129 if( person ) addritem_person_set_opened( person, FALSE );
3133 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3135 gchar *eMailAlias = ADDRITEM_NAME(email);
3136 if( eMailAlias && *eMailAlias != '\0' ) {
3138 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3141 str = g_strdup( eMailAlias );
3147 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3148 GList *items = itemGroup->listEMail;
3149 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3150 for( ; items != NULL; items = g_list_next( items ) ) {
3151 GtkCTreeNode *nodeEMail = NULL;
3152 gchar *text[N_LIST_COLS];
3153 ItemEMail *email = items->data;
3157 if( ! email ) continue;
3159 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3160 str = addressbook_format_item_clist( person, email );
3162 text[COL_NAME] = str;
3165 text[COL_NAME] = ADDRITEM_NAME(person);
3167 text[COL_ADDRESS] = email->address;
3168 text[COL_REMARKS] = email->remarks;
3169 nodeEMail = gtk_sctree_insert_node(
3171 text, FOLDER_SPACING,
3172 atci->iconXpm, atci->maskXpm,
3173 atci->iconXpmOpen, atci->maskXpmOpen,
3175 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3181 static void addressbook_folder_load_one_person(
3182 GtkCTree *clist, ItemPerson *person,
3183 AddressTypeControlItem *atci,
3184 AddressTypeControlItem *atciMail )
3186 GtkCTreeNode *nodePerson = NULL;
3187 GtkCTreeNode *nodeEMail = NULL;
3188 gchar *text[N_LIST_COLS];
3189 gboolean flgFirst = TRUE, haveAddr = FALSE;
3192 if( person == NULL ) return;
3194 text[COL_NAME] = "";
3195 node = person->listEMail;
3197 ItemEMail *email = node->data;
3198 gchar *eMailAddr = NULL;
3199 node = g_list_next( node );
3201 text[COL_ADDRESS] = email->address;
3202 text[COL_REMARKS] = email->remarks;
3203 eMailAddr = ADDRITEM_NAME(email);
3204 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3206 /* First email belongs with person */
3207 gchar *str = addressbook_format_item_clist( person, email );
3209 text[COL_NAME] = str;
3212 text[COL_NAME] = ADDRITEM_NAME(person);
3214 nodePerson = gtk_sctree_insert_node(
3216 text, FOLDER_SPACING,
3217 atci->iconXpm, atci->maskXpm,
3218 atci->iconXpmOpen, atci->maskXpmOpen,
3219 FALSE, person->isOpened );
3222 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3225 /* Subsequent email is a child node of person */
3226 text[COL_NAME] = ADDRITEM_NAME(email);
3227 nodeEMail = gtk_sctree_insert_node(
3228 clist, nodePerson, NULL,
3229 text, FOLDER_SPACING,
3230 atciMail->iconXpm, atciMail->maskXpm,
3231 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3233 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3239 /* Have name without EMail */
3240 text[COL_NAME] = ADDRITEM_NAME(person);
3241 text[COL_ADDRESS] = "";
3242 text[COL_REMARKS] = "";
3243 nodePerson = gtk_sctree_insert_node(
3245 text, FOLDER_SPACING,
3246 atci->iconXpm, atci->maskXpm,
3247 atci->iconXpmOpen, atci->maskXpmOpen,
3248 FALSE, person->isOpened );
3249 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3254 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3256 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3257 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3259 if( atci == NULL ) return;
3260 if( atciMail == NULL ) return;
3262 /* Load email addresses */
3263 items = addritem_folder_get_person_list( itemFolder );
3264 for( ; items != NULL; items = g_list_next( items ) ) {
3265 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );