2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2020 the Claws Mail team and Hiroyuki Yamamoto
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 3 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, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
47 #include "file-utils.h"
52 #include "addr_compl.h"
56 #include "addressitem.h"
58 #include "addrcache.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
77 #include "editjpilot.h"
82 #include "ldapserver.h"
84 #include "ldapupdate.h"
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
89 #include "addrquery.h"
90 #include "addrselect.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
105 } AddressIndexColumns;
113 } AddressListColumns;
116 AddressBookFile *book;
124 AddressDataSource *book;
128 static gchar *list_titles[] = { N_("Name"),
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
141 static GdkPixbuf *folderxpm = NULL;
142 static GdkPixbuf *folderopenxpm = NULL;
143 static GdkPixbuf *groupxpm = NULL;
144 static GdkPixbuf *interfacexpm = NULL;
145 static GdkPixbuf *bookxpm = NULL;
146 static GdkPixbuf *addressxpm = NULL;
147 static GdkPixbuf *vcardxpm = NULL;
148 static GdkPixbuf *jpilotxpm = NULL;
149 static GdkPixbuf *categoryxpm = NULL;
150 static GdkPixbuf *ldapxpm = NULL;
151 static GdkPixbuf *addrsearchxpm = NULL;
154 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
156 /* Address list selection */
157 static AddrSelectList *_addressSelect_ = NULL;
158 static AddressClipboard *_clipBoard_ = NULL;
160 /* Address index file and interfaces */
161 static AddressIndex *_addressIndex_ = NULL;
162 static GList *_addressInterfaceList_ = NULL;
163 static GList *_addressIFaceSelection_ = NULL;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
166 static AddressBook_win addrbook;
168 static GHashTable *_addressBookTypeHash_ = NULL;
169 static GList *_addressBookTypeList_ = NULL;
171 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
173 static void addressbook_edit_address_post_cb( ItemPerson *person );
175 static void addressbook_create (void);
176 static gint addressbook_close (void);
178 static gboolean address_index_has_focus = FALSE;
179 static gboolean address_list_has_focus = FALSE;
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton *button,
184 static void addressbook_reg_clicked (GtkButton *button,
186 static void addressbook_to_clicked (GtkButton *button,
188 static void addressbook_lup_clicked (GtkButton *button,
190 static void addressbook_close_clicked (GtkButton *button,
193 static void addressbook_tree_selected (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
197 static void addressbook_select_row_tree (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
201 static void addressbook_list_row_selected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
205 static void addressbook_list_row_unselected (GtkCMCTree *clist,
206 GtkCMCTreeNode *node,
209 static void addressbook_person_expand_node (GtkCMCTree *ctree,
212 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
216 static void addressbook_entry_activated (GtkWidget *widget,
219 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
220 GdkEventButton *event,
222 static gboolean addressbook_list_button_released(GtkWidget *widget,
223 GdkEventButton *event,
225 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
226 GdkEventButton *event,
228 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
229 GdkEventButton *event,
232 static void addressbook_new_folder_cb (GtkAction *action,
234 static void addressbook_new_group_cb (GtkAction *action,
236 static void addressbook_treenode_edit_cb (GtkAction *action,
238 static void addressbook_treenode_delete_cb (GtkAction *action,
241 static void addressbook_change_node_name (GtkCMCTreeNode *node,
244 static void addressbook_new_address_cb (GtkAction *action,
246 static void addressbook_edit_address_cb (GtkAction *action,
248 static void addressbook_delete_address_cb (GtkAction *action,
251 static void close_cb (GtkAction *action,
253 static void addressbook_file_save_cb (GtkAction *action,
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction *action,
259 static void addressbook_new_vcard_cb (GtkAction *action,
263 static void addressbook_new_jpilot_cb (GtkAction *action,
268 static void addressbook_new_ldap_cb (GtkAction *action,
272 static void addressbook_set_clist (AddressObject *obj,
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
278 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
280 static void addressbook_treenode_remove_item ( void );
282 static AddressDataSource *addressbook_find_datasource
283 (GtkCMCTreeNode *node );
285 static AddressBookFile *addressbook_get_book_file(void);
287 static GtkCMCTreeNode *addressbook_node_add_folder
288 (GtkCMCTreeNode *node,
289 AddressDataSource *ds,
290 ItemFolder *itemFolder,
291 AddressObjectType otype);
292 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
293 AddressDataSource *ds,
294 ItemGroup *itemGroup);
295 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
296 GtkCMCTreeNode *parent);
297 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
298 GtkCMCTreeNode *node);
299 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
301 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
304 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
307 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
309 AddressTypeControlItem *atci,
310 AddressTypeControlItem *atciMail);
311 static void addressbook_folder_remove_node (GtkCMCTree *clist,
312 GtkCMCTreeNode *node);
314 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
315 gboolean force_focus );
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data );
319 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
320 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
322 static void addrbookctl_build_map (GtkWidget *window);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
325 static void addrbookctl_build_ifselect (void);
327 static void addrbookctl_free_interface (AdapterInterface *adapter);
328 static void addrbookctl_free_datasource (AdapterDSource *adapter);
329 static void addrbookctl_free_folder (AdapterFolder *adapter);
330 static void addrbookctl_free_group (AdapterGroup *adapter);
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject *aio,
334 AddressDataSource *ds );
335 static void addressbook_list_select_remove ( AddrItemObject *aio );
337 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
338 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
339 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
344 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
352 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
356 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
358 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
360 static void addressbook_start_drag(GtkWidget *widget, gint button,
363 static void addressbook_drag_data_get(GtkWidget *widget,
364 GdkDragContext *drag_context,
365 GtkSelectionData *selection_data,
369 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
370 GdkDragContext *context,
375 static void addressbook_drag_leave_cb(GtkWidget *widget,
376 GdkDragContext *context,
379 static void addressbook_drag_received_cb(GtkWidget *widget,
380 GdkDragContext *drag_context,
383 GtkSelectionData *data,
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
394 static GtkTargetList *addressbook_target_list = NULL;
396 static void about_show_cb(GtkAction *action, gpointer data)
401 static GtkActionEntry addressbook_entries[] =
403 {"Menu", NULL, "Menu", NULL, NULL, NULL },
405 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
406 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
407 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
410 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
411 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
412 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
416 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
419 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
421 {"Book/---", NULL, "---", NULL, NULL, NULL },
423 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
424 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
425 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
426 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
427 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
430 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
431 {"Address/---", NULL, "---", NULL, NULL, NULL },
432 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
433 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
434 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
437 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
438 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
439 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
440 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
441 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
442 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
443 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
447 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
448 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
449 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
450 {"Tools/---", NULL, "---", NULL, NULL, NULL },
451 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
452 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
453 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
454 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
455 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
458 static GtkActionEntry addressbook_tree_popup_entries[] =
460 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
461 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
462 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
463 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
464 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
465 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
466 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
467 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
468 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
469 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
470 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
473 static GtkActionEntry addressbook_list_popup_entries[] =
475 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
476 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
477 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
478 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
479 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
482 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
483 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
484 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
485 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
486 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
490 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
492 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
496 * Structure of error message table.
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
499 struct _ErrMsgTableEntry {
504 static gchar *_errMsgUnknown_ = N_( "Unknown" );
507 * Lookup table of error messages for general errors. Note that a NULL
508 * description signifies the end of the table.
510 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
511 { MGU_SUCCESS, N_("Success") },
512 { MGU_BAD_ARGS, N_("Bad arguments") },
513 { MGU_NO_FILE, N_("File not specified") },
514 { MGU_OPEN_FILE, N_("Error opening file") },
515 { MGU_ERROR_READ, N_("Error reading file") },
516 { MGU_EOF, N_("End of file encountered") },
517 { MGU_OO_MEMORY, N_("Error allocating memory") },
518 { MGU_BAD_FORMAT, N_("Bad file format") },
519 { MGU_ERROR_WRITE, N_("Error writing to file") },
520 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
521 { MGU_NO_PATH, N_("No path specified") },
527 * Lookup table of error messages for LDAP errors.
529 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
530 { LDAPRC_SUCCESS, N_("Success") },
531 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
532 { LDAPRC_INIT, N_("Error initializing LDAP") },
533 { LDAPRC_BIND, N_("Error binding to LDAP server") },
534 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
535 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
536 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
537 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
538 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
539 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
540 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
541 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
542 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
543 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
549 * Lookup message for specified error code.
550 * \param lut Lookup table.
551 * \param code Code to lookup.
552 * \return Description associated to code.
554 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
556 ErrMsgTableEntry entry;
559 for( i = 0; ; i++ ) {
561 if( entry.description == NULL ) break;
562 if( entry.code == code ) {
563 desc = entry.description;
568 desc = _errMsgUnknown_;
573 static gboolean lastCanLookup = FALSE;
575 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
577 if (add_and_delete) {
578 gtk_widget_show(addrbook.edit_btn);
579 gtk_widget_show(addrbook.del_btn);
580 gtk_widget_show(addrbook.reg_btn);
582 gtk_widget_hide(addrbook.edit_btn);
583 gtk_widget_hide(addrbook.del_btn);
584 gtk_widget_hide(addrbook.reg_btn);
588 gtk_widget_show(addrbook.lup_btn);
589 gtk_widget_show(addrbook.entry);
590 gtk_widget_show(addrbook.label);
592 gtk_widget_hide(addrbook.lup_btn);
593 gtk_widget_hide(addrbook.entry);
594 gtk_widget_hide(addrbook.label);
597 lastCanLookup = lookup;
600 gtk_widget_show(addrbook.to_btn);
601 gtk_widget_show(addrbook.cc_btn);
602 gtk_widget_show(addrbook.bcc_btn);
604 gtk_widget_hide(addrbook.to_btn);
605 gtk_widget_hide(addrbook.cc_btn);
606 gtk_widget_hide(addrbook.bcc_btn);
610 void addressbook_open(Compose *target)
612 /* Initialize all static members */
613 if( _clipBoard_ == NULL ) {
614 _clipBoard_ = addrclip_create();
616 if( _addressIndex_ != NULL ) {
617 addrclip_set_index( _clipBoard_, _addressIndex_ );
619 if( _addressSelect_ == NULL ) {
620 _addressSelect_ = addrselect_list_create();
622 if (!addrbook.window) {
623 addressbook_read_file();
624 addressbook_create();
625 addressbook_load_tree();
626 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
627 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
630 gtk_widget_hide(addrbook.window);
633 gtk_widget_show_all(addrbook.window);
635 if (!prefs_common.addressbook_use_editaddress_dialog)
636 addressbook_edit_person_widgetset_hide();
638 address_completion_start(addrbook.window);
640 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
641 addressbook_set_target_compose(target);
645 * Destroy addressbook.
647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_ != NULL ) {
650 addrselect_list_free( _addressSelect_ );
652 if( _clipBoard_ != NULL ) {
653 addrclip_free( _clipBoard_ );
656 if( _addressIndex_ != NULL ) {
657 addrindex_free_index( _addressIndex_ );
658 addrindex_teardown();
660 _addressSelect_ = NULL;
662 _addressIndex_ = NULL;
665 void addressbook_set_target_compose(Compose *target)
667 addrbook.target_compose = target;
670 Compose *addressbook_get_target_compose(void)
672 return addrbook.target_compose;
676 * Refresh addressbook and save to file(s).
678 void addressbook_refresh( void )
680 if (addrbook.window) {
681 if (addrbook.treeSelected) {
682 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
683 addrbook.treeSelected);
684 addressbook_set_clist(
685 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
686 addrbook.treeSelected),
691 addressbook_export_to_file();
694 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
696 if (event && event->keyval == GDK_KEY_Escape)
698 else if (event && event->keyval == GDK_KEY_Delete) {
699 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
700 if ( /* address_index_has_focus || */ address_list_has_focus )
701 addressbook_del_clicked(NULL, NULL);
707 *\brief Save Gtk object size to prefs dataset
709 static void addressbook_size_allocate_cb(GtkWidget *widget,
710 GtkAllocation *allocation)
712 cm_return_if_fail(allocation != NULL);
714 prefs_common.addressbookwin_width = allocation->width;
715 prefs_common.addressbookwin_height = allocation->height;
718 static gint sort_column_number = 0;
719 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
721 static gint list_case_sort(
722 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
724 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
725 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
726 gchar *name1 = NULL, *name2 = NULL;
727 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
728 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
730 if( aio1->type == aio2->type ) {
732 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
734 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
735 if( ! name1 ) return ( name2 != NULL );
736 if( ! name2 ) return -1;
737 return g_utf8_collate( name1, name2 );
739 /* Order groups before person */
740 if( aio1->type == ITEMTYPE_GROUP ) {
741 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
742 } else if( aio2->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
749 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
750 const GtkSortType sort_type)
753 GtkWidget *hbox, *label, *arrow;
755 sort_column_number = col;
756 sort_column_type = sort_type;
757 gtk_cmclist_set_compare_func(clist, list_case_sort);
758 gtk_cmclist_set_sort_type(clist, sort_type);
759 gtk_cmclist_set_sort_column(clist, col);
761 gtk_cmclist_freeze(clist);
762 gtk_cmclist_sort(clist);
764 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
765 hbox = gtk_hbox_new(FALSE, 4);
766 label = gtk_label_new(gettext(list_titles[pos]));
767 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
770 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
771 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
772 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
775 gtk_widget_show_all(hbox);
776 gtk_cmclist_set_column_widget(clist, pos, hbox);
779 gtk_cmclist_thaw(clist);
782 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
784 static GtkSortType sort_type = GTK_SORT_ASCENDING;
786 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
788 addressbook_sort_list(clist, COL_NAME, sort_type);
791 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
793 static GtkSortType sort_type = GTK_SORT_ASCENDING;
795 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
797 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
800 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
802 static GtkSortType sort_type = GTK_SORT_ASCENDING;
804 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
806 addressbook_sort_list(clist, COL_REMARKS, sort_type);
809 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
812 address_index_has_focus = TRUE;
816 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
819 address_index_has_focus = FALSE;
820 if (!prefs_common.addressbook_use_editaddress_dialog
821 && !address_list_has_focus)
822 addressbook_address_list_disable_some_actions();
826 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
829 address_list_has_focus = TRUE;
833 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
836 address_list_has_focus = FALSE;
837 if (!prefs_common.addressbook_use_editaddress_dialog
838 && !address_index_has_focus)
839 addressbook_address_list_disable_some_actions();
843 /* save hpane and vpane's handle position when it moves */
844 static void addressbook_pane_save_position(void)
847 prefs_common.addressbook_hpaned_pos =
848 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
850 prefs_common.addressbook_vpaned_pos =
851 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
855 * Create the address book widgets. The address book contains two CTree widgets: the
856 * address index tree on the left and the address list on the right.
858 * The address index tree displays a hierarchy of interfaces and groups. Each node in
859 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
860 * data sources and folder objects.
862 * The address list displays group, person and email objects. These items are linked
863 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
866 * In the tradition of MVC architecture, the data stores have been separated from the
867 * GUI components. The addrindex.c file provides the interface to all data stores.
869 static void addressbook_create(void)
875 GtkWidget *ctree_swin;
877 GtkWidget *editaddress_vbox;
878 GtkWidget *clist_vbox;
879 GtkWidget *clist_swin;
886 GtkWidget *statusbar;
897 GtkWidget *close_btn;
898 GtkWidget *tree_popup;
899 GtkWidget *list_popup;
901 GtkUIManager *ui_manager;
902 GtkActionGroup *action_group;
903 gchar *index_titles[N_INDEX_COLS];
907 static GdkGeometry geometry;
909 debug_print("Creating addressbook window...\n");
911 index_titles[COL_SOURCES] = _("Sources");
913 /* Address book window */
914 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
915 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
916 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
917 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
918 gtk_widget_realize(window);
920 g_signal_connect(G_OBJECT(window), "delete_event",
921 G_CALLBACK(addressbook_close), NULL);
922 g_signal_connect(G_OBJECT(window), "size_allocate",
923 G_CALLBACK(addressbook_size_allocate_cb), NULL);
924 g_signal_connect(G_OBJECT(window), "key_press_event",
925 G_CALLBACK(key_pressed), NULL);
926 MANAGE_WINDOW_SIGNALS_CONNECT(window);
928 vbox = gtk_vbox_new(FALSE, 0);
929 gtk_container_add(GTK_CONTAINER(window), vbox);
932 ui_manager = gtk_ui_manager_new();
933 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
934 G_N_ELEMENTS(addressbook_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
936 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
937 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
938 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
990 gtk_window_add_accel_group(GTK_WINDOW(window),
991 gtk_ui_manager_get_accel_group(ui_manager));
993 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
995 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
997 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
998 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
999 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1001 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1002 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1003 GTK_POLICY_AUTOMATIC,
1004 GTK_POLICY_AUTOMATIC);
1005 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1008 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1009 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1011 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1012 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1013 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1014 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1015 GTK_CMCTREE_EXPANDER_TRIANGLE);
1016 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1017 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1018 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1019 addressbook_treenode_compare_func);
1021 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1022 G_CALLBACK(addressbook_tree_selected), NULL);
1023 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1024 G_CALLBACK(addressbook_tree_button_pressed),
1026 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1027 G_CALLBACK(addressbook_tree_button_released),
1030 g_signal_connect(G_OBJECT(ctree), "select_row",
1031 G_CALLBACK(addressbook_select_row_tree), NULL);
1033 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1034 addressbook_drag_types, 1,
1035 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1036 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1037 G_CALLBACK(addressbook_drag_motion_cb),
1039 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1040 G_CALLBACK(addressbook_drag_leave_cb),
1042 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1043 G_CALLBACK(addressbook_drag_received_cb),
1045 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1046 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1047 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1050 clist_vbox = gtk_vbox_new(FALSE, 4);
1052 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1053 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1054 GTK_POLICY_AUTOMATIC,
1055 GTK_POLICY_AUTOMATIC);
1056 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1059 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1060 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1061 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1062 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1063 GTK_CMCTREE_EXPANDER_TRIANGLE);
1064 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1065 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1066 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1068 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1070 gtk_widget_set_size_request(clist, -1, 80);
1072 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1073 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1074 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1075 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1076 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1077 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1078 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1079 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1080 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1081 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1082 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1084 for (i = 0; i < N_LIST_COLS; i++)
1085 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1088 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1089 G_CALLBACK(addressbook_list_row_selected), NULL);
1090 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1091 G_CALLBACK(addressbook_list_row_unselected), NULL);
1092 g_signal_connect(G_OBJECT(clist), "button_press_event",
1093 G_CALLBACK(addressbook_list_button_pressed),
1095 g_signal_connect(G_OBJECT(clist), "button_release_event",
1096 G_CALLBACK(addressbook_list_button_released),
1098 g_signal_connect(G_OBJECT(clist), "tree_expand",
1099 G_CALLBACK(addressbook_person_expand_node), NULL );
1100 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1101 G_CALLBACK(addressbook_person_collapse_node), NULL );
1102 g_signal_connect(G_OBJECT(clist), "start_drag",
1103 G_CALLBACK(addressbook_start_drag), NULL);
1104 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1105 G_CALLBACK(addressbook_drag_data_get), NULL);
1106 hbox = gtk_hbox_new(FALSE, 4);
1107 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1109 label = gtk_label_new(_("Search"));
1110 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1112 entry = gtk_entry_new();
1113 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1115 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1117 g_signal_connect(G_OBJECT(entry), "key_press_event",
1118 G_CALLBACK(addressbook_entry_key_pressed),
1120 g_signal_connect(G_OBJECT(entry), "activate",
1121 G_CALLBACK(addressbook_entry_activated), NULL);
1123 if (!prefs_common.addressbook_use_editaddress_dialog) {
1124 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1125 vpaned = gtk_vpaned_new();
1126 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1127 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1130 editaddress_vbox = NULL;
1132 hpaned = gtk_hpaned_new();
1133 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1134 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1135 if (prefs_common.addressbook_use_editaddress_dialog)
1136 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1138 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1141 hsbox = gtk_hbox_new(FALSE, 0);
1142 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1143 statusbar = gtk_statusbar_new();
1144 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1147 hbbox = gtk_hbutton_box_new();
1148 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1149 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1150 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1151 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1153 gtkut_stock_button_add_help(hbbox, &help_btn);
1155 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1156 gtk_widget_set_can_default(edit_btn, TRUE);
1157 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1158 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1159 gtk_widget_set_can_default(del_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1161 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1162 gtk_widget_set_can_default(reg_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1166 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1167 gtk_widget_set_can_default(lup_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1170 g_signal_connect(G_OBJECT(help_btn), "clicked",
1171 G_CALLBACK(manual_open_with_anchor_cb),
1172 MANUAL_ANCHOR_ADDRBOOK);
1174 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1175 G_CALLBACK(addressbook_edit_clicked), NULL);
1176 g_signal_connect(G_OBJECT(del_btn), "clicked",
1177 G_CALLBACK(addressbook_del_clicked), NULL);
1178 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1179 G_CALLBACK(addressbook_reg_clicked), NULL);
1180 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1181 G_CALLBACK(addressbook_lup_clicked), NULL);
1183 to_btn = gtk_button_new_with_label
1184 (prefs_common_translated_header_name("To:"));
1185 gtk_widget_set_can_default(to_btn, TRUE);
1186 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1187 cc_btn = gtk_button_new_with_label
1188 (prefs_common_translated_header_name("Cc:"));
1189 gtk_widget_set_can_default(cc_btn, TRUE);
1190 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1191 bcc_btn = gtk_button_new_with_label
1192 (prefs_common_translated_header_name("Bcc:"));
1193 gtk_widget_set_can_default(bcc_btn, TRUE);
1194 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1196 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1197 gtk_widget_set_can_default(close_btn, TRUE);
1198 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1200 g_signal_connect(G_OBJECT(to_btn), "clicked",
1201 G_CALLBACK(addressbook_to_clicked),
1202 GINT_TO_POINTER(COMPOSE_TO));
1203 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1204 G_CALLBACK(addressbook_to_clicked),
1205 GINT_TO_POINTER(COMPOSE_CC));
1206 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_BCC));
1209 g_signal_connect(G_OBJECT(close_btn), "clicked",
1210 G_CALLBACK(addressbook_close_clicked), NULL);
1212 /* Build icons for interface */
1214 /* Build control tables */
1215 addrbookctl_build_map(window);
1216 addrbookctl_build_iflist();
1217 addrbookctl_build_ifselect();
1219 addrbook.clist = NULL;
1221 /* Add each interface into the tree as a root level folder */
1222 nodeIf = _addressInterfaceList_;
1224 AdapterInterface *adapter = nodeIf->data;
1225 AddressInterface *iface = adapter->interface;
1226 nodeIf = g_list_next(nodeIf);
1228 if(iface->useInterface) {
1229 AddressTypeControlItem *atci = adapter->atci;
1230 text = atci->displayName;
1232 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1233 NULL, NULL, &text, FOLDER_SPACING,
1237 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1238 gtk_cmctree_node_set_row_data_full(
1239 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1240 addressbook_free_treenode );
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1259 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1260 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1280 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1281 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1283 addrbook.window = window;
1284 addrbook.hpaned = hpaned;
1285 addrbook.vpaned = vpaned;
1286 addrbook.menubar = menubar;
1287 addrbook.ctree = ctree;
1290 addrbook.editaddress_vbox = editaddress_vbox;
1291 addrbook.clist = clist;
1292 addrbook.label = label;
1293 addrbook.entry = entry;
1294 addrbook.statusbar = statusbar;
1295 addrbook.status_cid = gtk_statusbar_get_context_id(
1296 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1298 addrbook.help_btn = help_btn;
1299 addrbook.edit_btn = edit_btn;
1300 addrbook.del_btn = del_btn;
1301 addrbook.reg_btn = reg_btn;
1302 addrbook.lup_btn = lup_btn;
1303 addrbook.to_btn = to_btn;
1304 addrbook.cc_btn = cc_btn;
1305 addrbook.bcc_btn = bcc_btn;
1307 addrbook.tree_popup = tree_popup;
1308 addrbook.list_popup = list_popup;
1309 addrbook.ui_manager = ui_manager;
1311 addrbook.listSelected = NULL;
1313 if (!geometry.min_height) {
1314 geometry.min_width = ADDRESSBOOK_WIDTH;
1315 geometry.min_height = ADDRESSBOOK_HEIGHT;
1318 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1320 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1321 prefs_common.addressbookwin_height);
1323 gtk_window_move(GTK_WINDOW(window), 48, 48);
1326 if (!prefs_common.addressbook_use_editaddress_dialog) {
1327 if (prefs_common.addressbook_vpaned_pos > 0)
1328 gtk_paned_set_position(GTK_PANED(vpaned),
1329 prefs_common.addressbook_vpaned_pos);
1331 if (prefs_common.addressbook_hpaned_pos > 0)
1332 gtk_paned_set_position(GTK_PANED(hpaned),
1333 prefs_common.addressbook_hpaned_pos);
1336 gtk_widget_show_all(window);
1340 * Close address book window and save to file(s).
1342 static gint addressbook_close( void ) {
1343 address_completion_end(addrbook.window);
1344 if (!prefs_common.addressbook_use_editaddress_dialog)
1345 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1347 addressbook_pane_save_position();
1349 gtk_widget_hide(addrbook.window);
1350 addressbook_export_to_file();
1355 * Display message in status line.
1356 * \param msg Message to display.
1358 static void addressbook_status_show( gchar *msg ) {
1359 if( addrbook.statusbar != NULL ) {
1361 GTK_STATUSBAR(addrbook.statusbar),
1362 addrbook.status_cid );
1365 GTK_STATUSBAR(addrbook.statusbar),
1366 addrbook.status_cid, msg );
1371 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1375 *addressbook_msgbuf = '\0';
1377 name = addrindex_ds_get_name( ds );
1378 retVal = addrindex_ds_get_status_code( ds );
1379 if( retVal == MGU_SUCCESS ) {
1380 g_snprintf( addressbook_msgbuf,
1381 sizeof(addressbook_msgbuf), "%s", name );
1384 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1385 g_snprintf( addressbook_msgbuf,
1386 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1389 addressbook_status_show( addressbook_msgbuf );
1392 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1394 addressbook_edit_address_cb(NULL, NULL);
1397 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1399 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1403 * Delete one or more objects from address list.
1405 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1407 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1408 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1409 AddressObject *pobj;
1410 AdapterDSource *ads = NULL;
1411 GtkCMCTreeNode *nodeList;
1414 AddressBookFile *abf = NULL;
1415 AddressDataSource *ds = NULL;
1416 AddressInterface *iface;
1417 AddrItemObject *aio;
1418 AddrSelectItem *item;
1420 gboolean refreshList = FALSE;
1422 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1423 cm_return_if_fail(pobj != NULL);
1425 /* Test whether anything selected for deletion */
1426 nodeList = addrbook.listSelected;
1428 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1429 if( aio == NULL) return;
1430 ds = addressbook_find_datasource( addrbook.treeSelected );
1431 if( ds == NULL ) return;
1433 /* Test for read only */
1434 iface = ds->interface;
1435 if( iface->readOnly ) {
1436 alertpanel( _("Delete address(es)"),
1437 _("This address data is read-only and cannot be deleted."),
1438 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1442 /* Test whether Ok to proceed */
1444 if( pobj->type == ADDR_DATASOURCE ) {
1445 ads = ADAPTER_DSOURCE(pobj);
1446 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1448 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1451 else if( pobj->type == ADDR_ITEM_GROUP ) {
1454 if( ! procFlag ) return;
1455 abf = ds->rawDataSource;
1456 if( abf == NULL ) return;
1458 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1459 g_signal_handlers_block_by_func
1460 (G_OBJECT(addrbook.clist),
1461 G_CALLBACK(addressbook_list_row_unselected), NULL);
1463 /* Process deletions */
1464 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1465 GList *groups = NULL, *persons = NULL, *emails = NULL;
1466 gboolean group_delete = TRUE;
1467 /* Items inside folders */
1468 list = addrselect_get_list( _addressSelect_ );
1469 /* Confirm deletion */
1473 node = g_list_next( node );
1474 aio = ( AddrItemObject * ) item->addressItem;
1475 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1476 group_delete = FALSE;
1481 aval = alertpanel( _("Delete group"),
1482 _("Really delete the group(s)?\n"
1483 "The addresses it contains will not be lost."),
1484 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1485 if( aval != G_ALERTALTERNATE ) {
1489 aval = alertpanel( _("Delete address(es)"),
1490 _("Really delete the address(es)?"),
1491 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1492 if( aval != G_ALERTALTERNATE ) {
1497 /* first, set lists of groups and persons to remove */
1501 node = g_list_next( node );
1502 aio = ( AddrItemObject * ) item->addressItem;
1505 if( aio->type == ITEMTYPE_GROUP ) {
1506 groups = g_list_prepend(groups, item);
1508 else if( aio->type == ITEMTYPE_PERSON ) {
1509 persons = g_list_prepend(persons, item);
1512 /* then set list of emails to remove *if* they're not children of
1513 * persons to remove */
1517 node = g_list_next( node );
1518 aio = ( AddrItemObject * ) item->addressItem;
1521 if( aio->type == ITEMTYPE_EMAIL ) {
1522 ItemEMail *sitem = ( ItemEMail * ) aio;
1523 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1524 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1525 emails = g_list_prepend(emails, item);
1527 /* else, the email will be removed via the parent person */
1530 /* then delete groups */
1534 node = g_list_next( node );
1535 aio = ( AddrItemObject * ) item->addressItem;
1538 if( aio->type == ITEMTYPE_GROUP ) {
1539 ItemGroup *item = ( ItemGroup * ) aio;
1540 GtkCMCTreeNode *nd = NULL;
1541 nd = addressbook_find_group_node( addrbook.opened, item );
1542 item = addrbook_remove_group( abf, item );
1544 addritem_free_item_group( item );
1546 /* Remove group from parent node */
1547 gtk_cmctree_remove_node( ctree, nd );
1551 /* then delete persons */
1555 node = g_list_next( node );
1556 aio = ( AddrItemObject * ) item->addressItem;
1559 if( aio->type == ITEMTYPE_PERSON ) {
1560 ItemPerson *item = ( ItemPerson * ) aio;
1561 item->status = DELETE_ENTRY;
1562 addressbook_folder_remove_one_person( clist, item );
1563 if (pobj->type == ADDR_ITEM_FOLDER)
1564 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1565 item = addrbook_remove_person( abf, item );
1567 if (ds && ds->type == ADDR_IF_LDAP) {
1568 LdapServer *server = ds->rawDataSource;
1569 ldapsvr_set_modified(server, TRUE);
1570 ldapsvr_update_book(server, item);
1574 addritem_person_remove_picture(item);
1575 addritem_free_item_person( item );
1579 /* then delete emails */
1583 node = g_list_next( node );
1584 aio = ( AddrItemObject * ) item->addressItem;
1588 if( aio->type == ITEMTYPE_EMAIL ) {
1589 ItemEMail *sitem = ( ItemEMail * ) aio;
1590 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1591 sitem = addrbook_person_remove_email( abf, person, sitem );
1593 addrcache_remove_email(abf->addressCache, sitem);
1594 addritem_free_item_email( sitem );
1596 addressbook_folder_refresh_one_person( clist, person );
1599 g_list_free( groups );
1600 g_list_free( persons );
1601 g_list_free( emails );
1602 g_list_free( list );
1603 addressbook_list_select_clear();
1605 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1606 addressbook_set_clist(
1607 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1611 addrbook_set_dirty(abf, TRUE);
1612 addressbook_export_to_file();
1613 addressbook_list_menu_setup();
1616 else if( pobj->type == ADDR_ITEM_GROUP ) {
1617 /* Items inside groups */
1618 list = addrselect_get_list( _addressSelect_ );
1622 node = g_list_next( node );
1623 aio = ( AddrItemObject * ) item->addressItem;
1624 if( aio->type == ITEMTYPE_EMAIL ) {
1625 ItemEMail *item = ( ItemEMail * ) aio;
1626 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1627 item = addrbook_person_remove_email( abf, person, item );
1629 addritem_free_item_email( item );
1633 g_list_free( list );
1634 addressbook_list_select_clear();
1635 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1636 addressbook_set_clist(
1637 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1641 addrbook_set_dirty(abf, TRUE);
1642 addressbook_export_to_file();
1643 addressbook_list_menu_setup();
1647 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1648 gtk_cmctree_remove_node( clist, nodeList );
1650 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1651 g_signal_handlers_unblock_by_func
1652 (G_OBJECT(addrbook.clist),
1653 G_CALLBACK(addressbook_list_row_unselected), NULL);
1656 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1658 addressbook_new_address_cb( NULL, NULL );
1661 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1664 gchar *address = NULL;
1666 if( aio->type == ITEMTYPE_EMAIL ) {
1667 ItemPerson *person = NULL;
1668 ItemEMail *email = ( ItemEMail * ) aio;
1670 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1671 if( email->address ) {
1672 if( ADDRITEM_NAME(email) ) {
1673 name = ADDRITEM_NAME(email);
1674 if( *name == '\0' ) {
1675 name = ADDRITEM_NAME(person);
1678 else if( ADDRITEM_NAME(person) ) {
1679 name = ADDRITEM_NAME(person);
1682 buf = g_strdup( email->address );
1684 address = email->address;
1687 else if( aio->type == ITEMTYPE_PERSON ) {
1688 ItemPerson *person = ( ItemPerson * ) aio;
1689 GList *node = person->listEMail;
1691 name = ADDRITEM_NAME(person);
1693 ItemEMail *email = ( ItemEMail * ) node->data;
1694 address = email->address;
1698 if( name && name[0] != '\0' ) {
1699 if( strchr_with_skip_quote( name, '"', ',' ) )
1700 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1702 buf = g_strdup_printf( "%s <%s>", name, address );
1705 buf = g_strdup( address );
1712 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1716 AddrSelectItem *item;
1717 AddrItemObject *aio;
1720 compose = addrbook.target_compose;
1721 if( ! compose ) return;
1723 /* Nothing selected, but maybe there is something in text entry */
1724 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1726 compose_entry_append(
1727 compose, addr, (ComposeEntryType)data , PREF_NONE);
1730 /* Select from address list */
1731 list = addrselect_get_list( _addressSelect_ );
1736 node = g_list_next( node );
1737 aio = item->addressItem;
1738 if( aio->type == ITEMTYPE_PERSON ||
1739 aio->type == ITEMTYPE_EMAIL ) {
1740 addr = addressbook_format_address( aio );
1741 compose_entry_append(
1742 compose, addr, (ComposeEntryType) data, PREF_NONE );
1745 else if( aio->type == ITEMTYPE_GROUP ) {
1746 ItemGroup *group = ( ItemGroup * ) aio;
1747 GList *nodeMail = group->listEMail;
1749 ItemEMail *email = nodeMail->data;
1751 addr = addressbook_format_address(
1752 ( AddrItemObject * ) email );
1753 compose_entry_append(
1754 compose, addr, (ComposeEntryType) data, PREF_NONE );
1756 nodeMail = g_list_next( nodeMail );
1761 AddressObject *obj = NULL;
1763 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1765 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1766 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1767 GList *nodeMail = itemGroup->listEMail;
1769 ItemEMail *email = nodeMail->data;
1771 addr = addressbook_format_address(
1772 ( AddrItemObject * ) email );
1773 compose_entry_append(
1774 compose, addr, (ComposeEntryType) data, PREF_NONE );
1776 nodeMail = g_list_next( nodeMail );
1780 g_list_free( list );
1783 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1797 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1798 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1801 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1802 gboolean canEdit = FALSE;
1803 gboolean canDelete = TRUE;
1804 gboolean canAdd = FALSE;
1805 gboolean canEditTr = TRUE;
1806 gboolean editAddress = FALSE;
1807 gboolean canExport = TRUE;
1808 AddressTypeControlItem *atci = NULL;
1809 AddressDataSource *ds = NULL;
1810 AddressInterface *iface = NULL;
1812 if( obj == NULL ) return;
1813 if( obj->type == ADDR_INTERFACE ) {
1814 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1815 iface = adapter->interface;
1817 if( iface->haveLibrary ) {
1818 /* Enable appropriate File / New command */
1819 atci = adapter->atci;
1820 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1823 canEditTr = canExport = FALSE;
1825 else if( obj->type == ADDR_DATASOURCE ) {
1826 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1827 ds = ads->dataSource;
1828 iface = ds->interface;
1829 if( ! iface->readOnly ) {
1830 canAdd = canEdit = editAddress = canDelete = TRUE;
1832 if( ! iface->haveLibrary ) {
1833 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1836 else if( obj->type == ADDR_ITEM_FOLDER ) {
1837 ds = addressbook_find_datasource( addrbook.treeSelected );
1839 iface = ds->interface;
1840 if( iface->readOnly ) {
1845 canAdd = editAddress = TRUE;
1849 else if( obj->type == ADDR_ITEM_GROUP ) {
1850 ds = addressbook_find_datasource( addrbook.treeSelected );
1852 iface = ds->interface;
1853 if( ! iface->readOnly ) {
1859 if( addrbook.listSelected == NULL )
1863 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1865 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1866 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1871 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1872 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1883 * Address book tree callback function that responds to selection of tree
1886 * \param ctree Tree widget.
1887 * \param node Node that was selected.
1888 * \param column Column number where selected occurred.
1889 * \param data Pointer to user data.
1891 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1892 gint column, gpointer data)
1894 AddressObject *obj = NULL;
1895 AdapterDSource *ads = NULL;
1896 AddressDataSource *ds = NULL;
1897 ItemFolder *rootFolder = NULL;
1898 AddressObjectType aot;
1900 addrbook.treeSelected = node;
1901 addrbook.listSelected = NULL;
1902 addressbook_status_show( "" );
1903 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1905 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1907 addressbook_set_clist(NULL, TRUE);
1910 addrbook.opened = node;
1912 if( obj->type == ADDR_DATASOURCE ) {
1913 /* Read from file */
1914 static gboolean tVal = TRUE;
1916 ads = ADAPTER_DSOURCE(obj);
1918 ds = ads->dataSource;
1919 if( ds == NULL ) return;
1921 if( addrindex_ds_get_modify_flag( ds ) ) {
1922 addrindex_ds_read_data( ds );
1925 if( ! addrindex_ds_get_read_flag( ds ) ) {
1926 addrindex_ds_read_data( ds );
1928 addressbook_ds_show_message( ds );
1930 if( ! addrindex_ds_get_access_flag( ds ) ) {
1931 /* Remove existing folders and groups */
1932 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1933 addressbook_tree_remove_children( ctree, node );
1934 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1936 /* Load folders into the tree */
1937 rootFolder = addrindex_ds_get_root_folder( ds );
1938 if( ds && ds->type == ADDR_IF_JPILOT ) {
1939 aot = ADDR_CATEGORY;
1941 else if( ds && ds->type == ADDR_IF_LDAP ) {
1942 aot = ADDR_LDAP_QUERY;
1945 aot = ADDR_ITEM_FOLDER;
1947 addressbook_node_add_folder( node, ds, rootFolder, aot );
1948 addrindex_ds_set_access_flag( ds, &tVal );
1949 gtk_cmctree_expand( ctree, node );
1952 addressbook_set_clist(NULL, TRUE);
1955 /* Update address list */
1956 g_signal_handlers_block_by_func
1958 G_CALLBACK(addressbook_tree_selected), NULL);
1959 addressbook_set_clist( obj, FALSE );
1960 g_signal_handlers_unblock_by_func
1962 G_CALLBACK(addressbook_tree_selected), NULL);
1963 if (!prefs_common.addressbook_use_editaddress_dialog)
1964 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1966 /* Setup main menu selections */
1967 addressbook_menubar_set_sensitive( FALSE );
1968 addressbook_menuitem_set_sensitive( obj, node );
1969 addressbook_list_select_clear();
1970 addressbook_list_menu_setup();
1975 * Setup address list popup menu items. Items are enabled or disabled as
1978 static void addressbook_list_menu_setup( void ) {
1979 GtkCMCTree *clist = NULL;
1980 AddressObject *pobj = NULL;
1981 AddressObject *obj = NULL;
1982 AdapterDSource *ads = NULL;
1983 AddressInterface *iface = NULL;
1984 AddressDataSource *ds = NULL;
1986 AddrItemObject *aio;
1987 AddrSelectItem *item;
1988 gboolean canEdit = FALSE;
1989 gboolean canDelete = FALSE;
1990 gboolean canCut = FALSE;
1991 gboolean canCopy = FALSE;
1992 gboolean canPaste = FALSE;
1993 gboolean canBrowse = FALSE;
1994 gboolean canMerge = FALSE;
1996 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1997 if( pobj == NULL ) return;
1999 clist = GTK_CMCTREE(addrbook.clist);
2000 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2001 if( obj == NULL ) canEdit = FALSE;
2003 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2004 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2006 if( pobj->type == ADDR_DATASOURCE ) {
2007 /* Parent object is a data source */
2008 ads = ADAPTER_DSOURCE(pobj);
2009 ds = ads->dataSource;
2012 iface = ds->interface;
2015 if( ! iface->readOnly ) {
2016 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2017 if (iface->type != ADDR_IF_LDAP)
2018 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2019 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2022 canDelete = canEdit;
2025 else if( pobj->type != ADDR_INTERFACE ) {
2026 /* Parent object is not an interface */
2027 ds = addressbook_find_datasource( addrbook.treeSelected );
2030 iface = ds->interface;
2033 if( ! iface->readOnly ) {
2034 /* Folder or group */
2035 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2036 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2037 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2038 if( obj ) canEdit = TRUE;
2041 if( pobj->type == ADDR_ITEM_FOLDER ) {
2042 if (iface->type != ADDR_IF_LDAP)
2043 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2044 if( obj ) canEdit = TRUE;
2046 canDelete = canEdit;
2048 if( iface->type == ADDR_IF_LDAP ) {
2049 if( obj ) canBrowse = TRUE;
2056 /* Enable cut and paste */
2057 if( ! addrclip_is_empty( _clipBoard_ ) )
2059 if( ! addrselect_test_empty( _addressSelect_ ) )
2061 /* Enable copy if something is selected */
2062 if( ! addrselect_test_empty( _addressSelect_ ) )
2066 /* Disable edit or browse if more than one row selected */
2067 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2072 /* Allow merging persons or emails are selected */
2073 list = _addressSelect_->listSelect;
2074 if (list && list->next ) {
2076 aio = ( AddrItemObject * ) item->addressItem;
2077 if( aio->type == ITEMTYPE_EMAIL ||
2078 aio->type == ITEMTYPE_PERSON ) {
2083 /* Forbid write changes when read-only */
2084 if( iface && iface->readOnly ) {
2091 /* Now go finalize menu items */
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2111 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2112 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2114 if (addrbook.target_compose) {
2115 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2116 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2117 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2120 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2124 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2125 GtkCMCTreeNode *node,
2132 * Add list of items into tree node below specified tree node.
2133 * \param treeNode Tree node.
2134 * \param ds Data source.
2135 * \param listItems List of items.
2137 static void addressbook_treenode_add_list(
2138 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2144 AddrItemObject *aio;
2148 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2151 group = ( ItemGroup * ) aio;
2152 nn = addressbook_node_add_group( treeNode, ds, group );
2154 g_message("error adding addressbook group\n");
2157 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2160 folder = ( ItemFolder * ) aio;
2161 nn = addressbook_node_add_folder(
2162 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2164 g_message("error adding addressbook folder\n");
2167 node = g_list_next( node );
2171 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2172 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2176 * Cut from address list widget.
2178 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2179 _clipBoard_->cutFlag = TRUE;
2180 addrclip_clear( _clipBoard_ );
2181 addrclip_add( _clipBoard_, _addressSelect_ );
2182 /* addrclip_list_show( _clipBoard_, stdout ); */
2186 * Copy from address list widget.
2188 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2189 _clipBoard_->cutFlag = FALSE;
2190 addrclip_clear( _clipBoard_ );
2191 addrclip_add( _clipBoard_, _addressSelect_ );
2192 /* addrclip_list_show( _clipBoard_, stdout ); */
2196 * Paste clipboard into address list widget.
2198 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2199 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2200 AddressObject *pobj = NULL;
2201 AddressDataSource *ds = NULL;
2202 AddressBookFile *abf = NULL;
2203 ItemFolder *folder = NULL;
2204 GList *folderGroup = NULL;
2206 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2207 if( ds == NULL ) return;
2208 if( addrindex_ds_get_readonly( ds ) ) {
2209 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2213 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2215 if( pobj->type == ADDR_ITEM_FOLDER ) {
2216 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2218 else if( pobj->type == ADDR_ITEM_GROUP ) {
2219 alertpanel_error( _("Cannot paste into an address group.") );
2224 /* Get an address book */
2225 abf = addressbook_get_book_file();
2226 if( abf == NULL ) return;
2228 if( _clipBoard_->cutFlag ) {
2230 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2232 /* Remove all groups and folders in clipboard from tree node */
2233 addressbook_treenode_remove_item();
2235 /* Remove all "cut" items */
2236 addrclip_delete_item( _clipBoard_ );
2238 /* Clear clipboard - cut items??? */
2239 addrclip_clear( _clipBoard_ );
2243 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2246 /* addrclip_list_show( _clipBoard_, stdout ); */
2248 /* Update tree by inserting node for each folder or group */
2249 addressbook_treenode_add_list(
2250 addrbook.treeSelected, ds, folderGroup );
2251 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2252 g_list_free( folderGroup );
2256 /* Display items pasted */
2257 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2258 addressbook_set_clist(
2259 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2267 * Add current treenode object to clipboard. Note that widget only allows
2268 * one entry from the tree list to be selected.
2270 static void addressbook_treenode_to_clipboard( void ) {
2271 AddressObject *obj = NULL;
2272 AddressDataSource *ds = NULL;
2273 AddrSelectItem *item;
2274 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2275 GtkCMCTreeNode *node;
2277 node = addrbook.treeSelected;
2278 if( node == NULL ) return;
2279 obj = gtk_cmctree_node_get_row_data( ctree, node );
2280 if( obj == NULL ) return;
2282 ds = addressbook_find_datasource( node );
2283 if( ds == NULL ) return;
2286 if( obj->type == ADDR_ITEM_FOLDER ) {
2287 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2288 ItemFolder *folder = adapter->itemFolder;
2290 item = addrselect_create_node( obj );
2291 item->uid = g_strdup( ADDRITEM_ID(folder) );
2293 else if( obj->type == ADDR_ITEM_GROUP ) {
2294 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2295 ItemGroup *group = adapter->itemGroup;
2297 item = addrselect_create_node( obj );
2298 item->uid = g_strdup( ADDRITEM_ID(group) );
2300 else if( obj->type == ADDR_DATASOURCE ) {
2302 item = addrselect_create_node( obj );
2307 /* Clear existing list and add item into list */
2310 addressbook_list_select_clear();
2311 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2312 addrselect_list_add( _addressSelect_, item, cacheID );
2318 * Cut from tree widget.
2320 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2321 _clipBoard_->cutFlag = TRUE;
2322 addressbook_treenode_to_clipboard();
2323 addrclip_clear( _clipBoard_ );
2324 addrclip_add( _clipBoard_, _addressSelect_ );
2325 /* addrclip_list_show( _clipBoard_, stdout ); */
2329 * Copy from tree widget.
2331 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2332 _clipBoard_->cutFlag = FALSE;
2333 addressbook_treenode_to_clipboard();
2334 addrclip_clear( _clipBoard_ );
2335 addrclip_add( _clipBoard_, _addressSelect_ );
2336 /* addrclip_list_show( _clipBoard_, stdout ); */
2340 * Paste clipboard into address tree widget.
2342 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2343 addressbook_clip_paste_cb(NULL,NULL);
2347 * Clear selected entries in clipboard.
2349 static void addressbook_list_select_clear( void ) {
2350 addrselect_list_clear( _addressSelect_ );
2354 * Add specified address item to selected address list.
2355 * \param aio Address item object.
2356 * \param ds Datasource.
2358 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2361 if( ds == NULL ) return;
2362 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2363 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2368 * Remove specified address item from selected address list.
2369 * \param aio Address item object.
2371 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2372 addrselect_list_remove( _addressSelect_, aio );
2376 * Invoke EMail compose window with addresses in selected address list.
2378 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2381 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2382 listAddress = addrselect_build_list( _addressSelect_ );
2383 compose_new_with_list( NULL, listAddress );
2384 g_list_free_full( listAddress, g_free );
2389 static void addressbook_merge_list( AddrSelectList *list ) {
2390 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2391 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2392 AddressObject *pobj;
2393 AddressDataSource *ds = NULL;
2395 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2396 cm_return_if_fail(pobj != NULL);
2398 ds = addressbook_find_datasource( addrbook.treeSelected );
2399 if( ds == NULL ) return;
2401 addrmerge_merge(clist, pobj, ds, list);
2405 * Merge selected entries in the address list
2407 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2408 if( addrselect_test_empty( _addressSelect_ ) )
2411 addressbook_merge_list( _addressSelect_ );
2414 static void addressbook_list_row_selected( GtkCMCTree *clist,
2415 GtkCMCTreeNode *node,
2419 AddrItemObject *aio = NULL;
2420 AddressObject *pobj = NULL;
2421 AdapterDSource *ads = NULL;
2422 AddressDataSource *ds = NULL;
2424 addrbook.listSelected = node;
2426 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2427 if( pobj == NULL ) return;
2429 if( pobj->type == ADDR_DATASOURCE ) {
2430 ads = ADAPTER_DSOURCE(pobj);
2431 ds = ads->dataSource;
2433 else if( pobj->type != ADDR_INTERFACE ) {
2434 ds = addressbook_find_datasource( addrbook.treeSelected );
2437 aio = gtk_cmctree_node_get_row_data( clist, node );
2439 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2440 addressbook_list_select_add( aio, ds );
2443 addressbook_list_menu_setup();
2445 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2446 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2448 if (obj && obj->type != ADDR_ITEM_GROUP)
2449 addressbook_edit_address(NULL, 0, NULL, FALSE);
2453 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2454 GtkCMCTreeNode *node,
2458 AddrItemObject *aio;
2460 aio = gtk_cmctree_node_get_row_data( ctree, node );
2462 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2463 addressbook_list_select_remove( aio );
2466 if (!prefs_common.addressbook_use_editaddress_dialog)
2467 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2470 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2472 addressbook_lup_clicked(NULL, NULL);
2475 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2476 GdkEventButton *event,
2479 if( ! event ) return FALSE;
2480 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2482 addressbook_list_menu_setup();
2484 if( event->button == 3 ) {
2485 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2486 event->button, event->time );
2487 } else if (event->button == 1) {
2488 if (event->type == GDK_2BUTTON_PRESS) {
2489 if (prefs_common.add_address_by_click &&
2490 addrbook.target_compose)
2491 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2493 if (prefs_common.addressbook_use_editaddress_dialog)
2494 addressbook_edit_address_cb(NULL, NULL);
2496 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2497 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2498 if( obj && obj->type == ADDR_ITEM_GROUP )
2499 addressbook_edit_address_cb(NULL, NULL);
2507 static gboolean addressbook_list_button_released(GtkWidget *widget,
2508 GdkEventButton *event,
2514 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2515 GdkEventButton *event,
2518 GtkCMCList *clist = GTK_CMCLIST(ctree);
2520 AddressObject *obj = NULL;
2521 AdapterDSource *ads = NULL;
2522 AddressInterface *iface = NULL;
2523 AddressDataSource *ds = NULL;
2524 gboolean canEdit = FALSE;
2525 gboolean canDelete = FALSE;
2526 gboolean canCut = FALSE;
2527 gboolean canCopy = FALSE;
2528 gboolean canPaste = FALSE;
2529 gboolean canTreeCut = FALSE;
2530 gboolean canTreeCopy = FALSE;
2531 gboolean canTreePaste = FALSE;
2532 gboolean canLookup = FALSE;
2533 GtkCMCTreeNode *node = NULL;
2535 if( ! event ) return FALSE;
2536 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2538 if( event->window != clist->clist_window )
2541 if (event->button == 1) {
2542 if (event->type == GDK_2BUTTON_PRESS) {
2543 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2544 gtkut_clist_set_focus_row(clist, row);
2545 obj = gtk_cmclist_get_row_data( clist, row );
2550 if (obj->type == ADDR_ITEM_GROUP ||
2551 obj->type == ADDR_DATASOURCE) {
2553 addressbook_treenode_edit_cb(NULL, NULL);
2555 /* expand pr collapse */
2556 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2557 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2563 addressbook_menubar_set_sensitive( FALSE );
2565 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2566 gtkut_clist_set_focus_row(clist, row);
2567 obj = gtk_cmclist_get_row_data( clist, row );
2570 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2574 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2576 if( ! addrclip_is_empty( _clipBoard_ ) )
2577 canTreePaste = TRUE;
2579 if (obj->type == ADDR_INTERFACE) {
2580 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2581 iface = adapter->interface;
2584 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2585 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2587 if( iface->externalQuery )
2590 if (obj->type == ADDR_DATASOURCE) {
2592 ads = ADAPTER_DSOURCE(obj);
2593 ds = ads->dataSource;
2596 iface = ds->interface;
2599 if( !iface->readOnly ) {
2600 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2601 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2602 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2608 else if (obj->type == ADDR_ITEM_FOLDER) {
2610 ds = addressbook_find_datasource( node );
2613 iface = ds->interface;
2616 if( !iface->readOnly ) {
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2622 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2626 if( iface->externalQuery ) {
2627 /* Enable deletion of LDAP folder */
2631 else if (obj->type == ADDR_ITEM_GROUP) {
2633 ds = addressbook_find_datasource( node );
2636 iface = ds->interface;
2639 if( ! iface->readOnly ) {
2642 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2643 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2647 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2649 if( ! addrselect_test_empty( _addressSelect_ ) )
2651 if( ! addrclip_is_empty( _clipBoard_ ) )
2654 /* Forbid write changes when read-only */
2655 if( iface && iface->readOnly ) {
2657 canTreePaste = FALSE;
2664 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2665 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2671 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2672 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2676 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2677 addrbook.target_compose != NULL);
2679 if( event->button == 3 )
2680 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2681 event->button, event->time);
2686 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2687 GdkEventButton *event,
2690 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2694 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2696 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2697 AddressObject *obj = NULL;
2698 AddressDataSource *ds = NULL;
2699 AddressBookFile *abf = NULL;
2700 ItemFolder *parentFolder = NULL;
2701 ItemFolder *folder = NULL;
2703 if( ! addrbook.treeSelected ) return;
2704 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2705 if( obj == NULL ) return;
2706 ds = addressbook_find_datasource( addrbook.treeSelected );
2707 if( ds == NULL ) return;
2709 if( obj->type == ADDR_DATASOURCE ) {
2710 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2712 else if( obj->type == ADDR_ITEM_FOLDER ) {
2713 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2719 abf = ds->rawDataSource;
2720 if( abf == NULL ) return;
2721 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2724 nn = addressbook_node_add_folder(
2725 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2727 g_message("error adding addressbook folder\n");
2729 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2730 if( addrbook.treeSelected == addrbook.opened )
2731 addressbook_set_clist(obj, TRUE);
2735 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2737 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2738 AddressObject *obj = NULL;
2739 AddressDataSource *ds = NULL;
2740 AddressBookFile *abf = NULL;
2741 ItemFolder *parentFolder = NULL;
2742 ItemGroup *group = NULL;
2744 if( ! addrbook.treeSelected ) return;
2745 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2746 if( obj == NULL ) return;
2747 ds = addressbook_find_datasource( addrbook.treeSelected );
2748 if( ds == NULL ) return;
2750 if( obj->type == ADDR_DATASOURCE ) {
2751 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2753 else if( obj->type == ADDR_ITEM_FOLDER ) {
2754 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2760 abf = ds->rawDataSource;
2761 if( abf == NULL ) return;
2762 group = addressbook_edit_group( abf, parentFolder, NULL );
2765 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2767 g_message("error adding addressbook group\n");
2769 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2770 if( addrbook.treeSelected == addrbook.opened )
2771 addressbook_set_clist(obj, TRUE);
2775 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2777 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2780 GdkPixbuf *pix_cl, *pix_op;
2781 gboolean is_leaf, expanded;
2783 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2785 &is_leaf, &expanded);
2786 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2793 * \param obj Address object to edit.
2794 * \param node Node in tree.
2795 * \return New name of data source.
2797 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2798 gchar *newName = NULL;
2799 AddressDataSource *ds = NULL;
2800 AddressInterface *iface = NULL;
2801 AdapterDSource *ads = NULL;
2803 ds = addressbook_find_datasource( node );
2804 if( ds == NULL ) return NULL;
2805 iface = ds->interface;
2806 if( ! iface->haveLibrary ) return NULL;
2808 /* Read data from data source */
2809 if( addrindex_ds_get_modify_flag( ds ) ) {
2810 addrindex_ds_read_data( ds );
2813 if( ! addrindex_ds_get_read_flag( ds ) ) {
2814 addrindex_ds_read_data( ds );
2818 ads = ADAPTER_DSOURCE(obj);
2819 if( ads->subType == ADDR_BOOK ) {
2820 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2822 else if( ads->subType == ADDR_VCARD ) {
2823 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2826 else if( ads->subType == ADDR_JPILOT ) {
2827 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2831 else if( ads->subType == ADDR_LDAP ) {
2832 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2838 newName = obj->name;
2843 * Edit an object that is in the address tree area.
2845 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2847 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2849 AddressDataSource *ds = NULL;
2850 AddressBookFile *abf = NULL;
2851 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2854 if( ! addrbook.treeSelected ) return;
2855 node = addrbook.treeSelected;
2856 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2857 obj = gtk_cmctree_node_get_row_data( ctree, node );
2858 if( obj == NULL ) return;
2859 parentNode = GTK_CMCTREE_ROW(node)->parent;
2861 ds = addressbook_find_datasource( node );
2862 if( ds == NULL ) return;
2864 if( obj->type == ADDR_DATASOURCE ) {
2865 name = addressbook_edit_datasource( obj, node );
2866 if( name == NULL ) return;
2869 abf = ds->rawDataSource;
2870 if( abf == NULL ) return;
2871 if( obj->type == ADDR_ITEM_FOLDER ) {
2872 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2873 ItemFolder *item = adapter->itemFolder;
2874 ItemFolder *parentFolder = NULL;
2875 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2876 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2877 name = ADDRITEM_NAME(item);
2879 else if( obj->type == ADDR_ITEM_GROUP ) {
2880 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2881 ItemGroup *item = adapter->itemGroup;
2882 ItemFolder *parentFolder = NULL;
2883 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2884 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2885 name = ADDRITEM_NAME(item);
2888 if( name && parentNode ) {
2889 /* Update node in tree view */
2890 addressbook_change_node_name( node, name );
2891 gtk_sctree_sort_node(ctree, parentNode);
2892 gtk_cmctree_expand( ctree, node );
2893 gtk_sctree_select( GTK_SCTREE( ctree), node );
2900 ADDRTREE_DEL_FOLDER_ONLY,
2901 ADDRTREE_DEL_FOLDER_ADDR
2905 * Delete an item from the tree widget.
2906 * \param data Data passed in.
2907 * \param action Action.
2908 * \param widget Widget issuing callback.
2910 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2912 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2913 GtkCMCTreeNode *node = NULL;
2917 AddrBookBase *adbase;
2918 AddressCache *cache;
2919 AdapterDSource *ads = NULL;
2920 AddressInterface *iface = NULL;
2921 AddressDataSource *ds = NULL;
2922 gboolean remFlag = FALSE;
2923 TreeItemDelType delType;
2925 if( ! addrbook.treeSelected ) return;
2926 node = addrbook.treeSelected;
2927 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2929 obj = gtk_cmctree_node_get_row_data( ctree, node );
2930 cm_return_if_fail(obj != NULL);
2932 if( obj->type == ADDR_DATASOURCE ) {
2933 ads = ADAPTER_DSOURCE(obj);
2935 ds = ads->dataSource;
2936 if( ds == NULL ) return;
2939 /* Must be folder or something else */
2940 ds = addressbook_find_datasource( node );
2941 if( ds == NULL ) return;
2943 /* Only allow deletion from non-readOnly */
2944 iface = ds->interface;
2945 if( iface->readOnly ) {
2946 /* Allow deletion of query results */
2947 if( ! iface->externalQuery ) return;
2951 /* Confirm deletion */
2952 delType = ADDRTREE_DEL_NONE;
2953 if( obj->type == ADDR_ITEM_FOLDER ) {
2954 if( iface && iface->externalQuery ) {
2955 message = g_strdup_printf( _(
2956 "Do you want to delete the query " \
2957 "results and addresses in '%s'?" ),
2959 aval = alertpanel( _("Delete"), message,
2960 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2962 if( aval == G_ALERTALTERNATE ) {
2963 delType = ADDRTREE_DEL_FOLDER_ADDR;
2967 message = g_strdup_printf
2968 ( _( "Do you want to delete '%s'? "
2969 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2971 aval = alertpanel( _("Delete folder"), message,
2972 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2974 if( aval == G_ALERTALTERNATE ) {
2975 delType = ADDRTREE_DEL_FOLDER_ONLY;
2977 else if( aval == G_ALERTOTHER ) {
2978 delType = ADDRTREE_DEL_FOLDER_ADDR;
2982 else if( obj->type == ADDR_ITEM_GROUP ) {
2983 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2984 "The addresses it contains will not be lost."), obj->name);
2985 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2986 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2988 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2990 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2991 "The addresses it contains will be lost."), obj->name);
2992 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2993 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2995 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2997 if( delType == ADDRTREE_DEL_NONE ) return;
2999 /* Proceed with deletion */
3000 if( obj->type == ADDR_DATASOURCE ) {
3001 /* Remove node from tree */
3002 gtk_cmctree_remove_node( ctree, node );
3004 if (delType == ADDRTREE_DEL_DATA &&
3005 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3006 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3008 /* Remove data source. */
3009 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3010 addrindex_free_datasource( ds );
3015 /* Get reference to cache */
3016 adbase = ( AddrBookBase * ) ds->rawDataSource;
3017 if( adbase == NULL ) return;
3018 cache = adbase->addressCache;
3020 /* Remove query results folder */
3021 if( iface && iface->externalQuery ) {
3022 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3023 ItemFolder *folder = adapter->itemFolder;
3025 adapter->itemFolder = NULL;
3027 g_print( "remove folder for ::%s::\n", obj->name );
3028 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3029 g_print( "-------------- remove results\n" );
3031 addrindex_remove_results( ds, folder );
3032 /* g_print( "-------------- remove node\n" ); */
3033 gtk_cmctree_remove_node( ctree, node );
3037 /* Code below is valid for regular address book deletion */
3038 if( obj->type == ADDR_ITEM_FOLDER ) {
3039 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3040 ItemFolder *item = adapter->itemFolder;
3042 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3043 /* Remove folder only */
3044 item = addrcache_remove_folder( cache, item );
3046 addritem_free_item_folder( item );
3047 addressbook_move_nodes_up( ctree, node );
3051 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3052 /* Remove folder and addresses */
3053 item = addrcache_remove_folder_delete( cache, item );
3055 addritem_free_item_folder( item );
3060 else if( obj->type == ADDR_ITEM_GROUP ) {
3061 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3062 ItemGroup *item = adapter->itemGroup;
3064 item = addrcache_remove_group( cache, item );
3066 addritem_free_item_group( item );
3073 gtk_cmctree_remove_node(ctree, node );
3077 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3079 if( person && addrbook.treeSelected == addrbook.opened ) {
3080 person->status = ADD_ENTRY;
3081 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3082 addressbook_folder_refresh_one_person(
3083 GTK_CMCTREE(addrbook.clist), person );
3085 addressbook_address_list_set_focus();
3088 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3090 if( person && addrbook.treeSelected == addrbook.opened) {
3091 person->status = ADD_ENTRY;
3092 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3093 addressbook_set_clist(
3094 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3098 addressbook_address_list_set_focus();
3102 * Label (a format string) that is used to name each folder.
3104 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3107 * Search ctree widget callback function.
3108 * \param pA Pointer to node.
3109 * \param pB Pointer to data item being sought.
3110 * \return Zero (0) if folder found.
3112 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3115 aoA = ( AddressObject * ) pA;
3116 if( aoA->type == ADDR_ITEM_FOLDER ) {
3117 ItemFolder *folder, *fld;
3119 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3120 folder = ( ItemFolder * ) pB;
3121 if( fld == folder ) return 0; /* Found folder */
3126 static ItemFolder * addressbook_setup_subf(
3127 AddressDataSource *ds, gchar *title,
3128 GtkCMCTreeNode *pNode )
3130 AddrBookBase *adbase;
3131 AddressCache *cache;
3134 GtkCMCTreeNode *nNode;
3136 AddressObjectType aoType = ADDR_NONE;
3139 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3141 if( ds && ds->type == ADDR_IF_LDAP ) {
3143 aoType = ADDR_LDAP_QUERY;
3150 ctree = GTK_CMCTREE(addrbook.ctree);
3151 /* Get reference to address cache */
3152 adbase = ( AddrBookBase * ) ds->rawDataSource;
3153 cache = adbase->addressCache;
3155 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3156 GList *cur = children;
3157 for (; cur; cur = cur->next) {
3158 ItemFolder *child = (ItemFolder *) cur->data;
3159 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3160 nNode = gtk_cmctree_find_by_row_data_custom(
3162 addressbook_treenode_find_folder_cb );
3164 addrindex_remove_results( ds, child );
3165 while( child->listPerson ) {
3166 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3167 item = addrcache_remove_person( cache, item );
3169 addritem_free_item_person( item );
3173 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3174 addrbook.treeSelected = nNode;
3181 /* Create a folder */
3182 folder = addrcache_add_new_folder( cache, NULL );
3183 name = g_strdup_printf( "%s", title );
3184 addritem_folder_set_name( folder, name );
3185 addritem_folder_set_remarks( folder, "" );
3188 /* Now let's see the folder */
3189 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3190 gtk_cmctree_expand( ctree, pNode );
3192 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3193 addrbook.treeSelected = nNode;
3199 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3200 AddressObject *pobj = NULL;
3201 AddressDataSource *ds = NULL;
3202 AddressBookFile *abf = NULL;
3203 debug_print("adding address\n");
3204 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3205 if( pobj == NULL ) {
3206 debug_print("no row data\n");
3209 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3211 debug_print("no datasource\n");
3215 abf = ds->rawDataSource;
3217 g_print("no addressbook file\n");
3221 if( pobj->type == ADDR_DATASOURCE ) {
3222 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3223 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3225 ItemFolder *folder = NULL;
3227 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3228 GtkCMCTreeNode *parentNode;
3229 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3230 if( ds == NULL ) return;
3232 /* We must have a datasource that is an external interface */
3233 if( ! ds->interface->haveLibrary ) return;
3234 if( ! ds->interface->externalQuery ) return;
3236 if( pobj->type == ADDR_ITEM_FOLDER ) {
3237 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3240 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3242 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3244 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );