2006-12-12 [paul] 2.6.1cvs21
[claws.git] / src / addressbook.c
blob9b8c705431b92e964b794603cd0df8577b7f5936
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #include "defs.h"
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
45 #include <string.h>
46 #include <setjmp.h>
48 #include "main.h"
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
54 #include "menu.h"
55 #include "stock_pixmap.h"
56 #include "xml.h"
57 #include "prefs_gtk.h"
58 #include "procmime.h"
59 #include "utils.h"
60 #include "gtkutils.h"
61 #include "codeconv.h"
62 #include "about.h"
63 #include "addr_compl.h"
65 #include "mgutils.h"
66 #include "addressitem.h"
67 #include "addritem.h"
68 #include "addrcache.h"
69 #include "addrbook.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addressbook_foldersel.h"
73 #include "vcard.h"
74 #include "editvcard.h"
75 #include "editgroup.h"
76 #include "editaddress.h"
77 #include "editbook.h"
78 #include "importldif.h"
79 #include "importmutt.h"
80 #include "importpine.h"
81 #include "manual.h"
83 #ifdef USE_JPILOT
84 #include "jpilot.h"
85 #include "editjpilot.h"
86 #endif
88 #ifdef USE_LDAP
89 #include <pthread.h>
90 #include "ldapserver.h"
91 #include "editldap.h"
93 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
94 #endif
96 #include "addrquery.h"
97 #include "addrselect.h"
98 #include "addrclip.h"
99 #include "addrgather.h"
100 #include "adbookbase.h"
101 #include "exphtmldlg.h"
102 #include "expldifdlg.h"
103 #include "browseldap.h"
105 typedef enum
107 COL_SOURCES = 0,
108 N_INDEX_COLS = 1
109 } AddressIndexColumns;
111 typedef enum
113 COL_NAME = 0,
114 COL_ADDRESS = 1,
115 COL_REMARKS = 2,
116 N_LIST_COLS = 3
117 } AddressListColumns;
119 typedef struct {
120 AddressBookFile *book;
121 ItemFolder *folder;
122 } FolderInfo;
124 typedef struct {
125 gchar **folder_path;
126 gboolean matched;
127 gint index;
128 AddressDataSource *book;
129 ItemFolder *folder;
130 } FolderPathMatch;
132 static gchar *list_titles[] = { N_("Name"),
133 N_("Email Address"),
134 N_("Remarks") };
136 #define COL_NAME_WIDTH 164
137 #define COL_ADDRESS_WIDTH 156
139 #define COL_FOLDER_WIDTH 170
140 #define ADDRESSBOOK_WIDTH 640
141 #define ADDRESSBOOK_HEIGHT 360
143 #define ADDRESSBOOK_MSGBUF_SIZE 2048
145 static GdkPixmap *folderxpm;
146 static GdkBitmap *folderxpmmask;
147 static GdkPixmap *folderopenxpm;
148 static GdkBitmap *folderopenxpmmask;
149 static GdkPixmap *groupxpm;
150 static GdkBitmap *groupxpmmask;
151 static GdkPixmap *interfacexpm;
152 static GdkBitmap *interfacexpmmask;
153 static GdkPixmap *bookxpm;
154 static GdkBitmap *bookxpmmask;
155 static GdkPixmap *addressxpm;
156 static GdkBitmap *addressxpmmask;
157 static GdkPixmap *vcardxpm;
158 static GdkBitmap *vcardxpmmask;
159 static GdkPixmap *jpilotxpm;
160 static GdkBitmap *jpilotxpmmask;
161 static GdkPixmap *categoryxpm;
162 static GdkBitmap *categoryxpmmask;
163 static GdkPixmap *ldapxpm;
164 static GdkBitmap *ldapxpmmask;
165 static GdkPixmap *addrsearchxpm;
166 static GdkPixmap *addrsearchxpmmask;
168 /* Message buffer */
169 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
171 /* Address list selection */
172 static AddrSelectList *_addressSelect_ = NULL;
173 static AddressClipboard *_clipBoard_ = NULL;
175 /* Address index file and interfaces */
176 static AddressIndex *_addressIndex_ = NULL;
177 static GList *_addressInterfaceList_ = NULL;
178 static GList *_addressIFaceSelection_ = NULL;
179 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
181 static AddressBook_win addrbook;
183 static GHashTable *_addressBookTypeHash_ = NULL;
184 static GList *_addressBookTypeList_ = NULL;
186 static void addressbook_create (void);
187 static gint addressbook_close (void);
188 static void addressbook_button_set_sensitive (void);
190 static gboolean address_index_has_focus = FALSE;
191 static gboolean address_list_has_focus = FALSE;
193 /* callback functions */
194 static void addressbook_del_clicked (GtkButton *button,
195 gpointer data);
196 static void addressbook_reg_clicked (GtkButton *button,
197 gpointer data);
198 static void addressbook_to_clicked (GtkButton *button,
199 gpointer data);
200 static void addressbook_lup_clicked (GtkButton *button,
201 gpointer data);
202 static void addressbook_close_clicked (GtkButton *button,
203 gpointer data);
205 static void addressbook_tree_selected (GtkCTree *ctree,
206 GtkCTreeNode *node,
207 gint column,
208 gpointer data);
209 static void addressbook_select_row_tree (GtkCTree *ctree,
210 GtkCTreeNode *node,
211 gint column,
212 gpointer data);
213 static void addressbook_list_row_selected (GtkCTree *clist,
214 GtkCTreeNode *node,
215 gint column,
216 gpointer data);
217 static void addressbook_list_row_unselected (GtkCTree *clist,
218 GtkCTreeNode *node,
219 gint column,
220 gpointer data);
221 static void addressbook_person_expand_node (GtkCTree *ctree,
222 GList *node,
223 gpointer *data );
224 static void addressbook_person_collapse_node (GtkCTree *ctree,
225 GList *node,
226 gpointer *data );
228 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
229 GdkEventButton *event,
230 gpointer data);
231 static gboolean addressbook_list_button_released(GtkWidget *widget,
232 GdkEventButton *event,
233 gpointer data);
234 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
235 GdkEventButton *event,
236 gpointer data);
237 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
238 GdkEventButton *event,
239 gpointer data);
241 static void addressbook_new_folder_cb (gpointer data,
242 guint action,
243 GtkWidget *widget);
244 static void addressbook_new_group_cb (gpointer data,
245 guint action,
246 GtkWidget *widget);
247 static void addressbook_treenode_edit_cb (gpointer data,
248 guint action,
249 GtkWidget *widget);
250 static void addressbook_treenode_delete_cb (gpointer data,
251 guint action,
252 GtkWidget *widget);
254 static void addressbook_change_node_name (GtkCTreeNode *node,
255 const gchar *name);
257 static void addressbook_new_address_cb (gpointer data,
258 guint action,
259 GtkWidget *widget);
260 static void addressbook_edit_address_cb (gpointer data,
261 guint action,
262 GtkWidget *widget);
263 static void addressbook_delete_address_cb (gpointer data,
264 guint action,
265 GtkWidget *widget);
267 static void close_cb (gpointer data,
268 guint action,
269 GtkWidget *widget);
270 static void addressbook_file_save_cb (gpointer data,
271 guint action,
272 GtkWidget *widget);
274 /* Data source edit stuff */
275 static void addressbook_new_book_cb (gpointer data,
276 guint action,
277 GtkWidget *widget);
278 static void addressbook_new_vcard_cb (gpointer data,
279 guint action,
280 GtkWidget *widget);
282 #ifdef USE_JPILOT
283 static void addressbook_new_jpilot_cb (gpointer data,
284 guint action,
285 GtkWidget *widget);
286 #endif
288 #ifdef USE_LDAP
289 static void addressbook_new_ldap_cb (gpointer data,
290 guint action,
291 GtkWidget *widget);
292 #endif
294 static void addressbook_set_clist (AddressObject *obj,
295 gboolean refresh);
297 static void addressbook_load_tree (void);
298 void addressbook_read_file (void);
300 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
301 AddressObject *obj);
302 static void addressbook_treenode_remove_item ( void );
304 static AddressDataSource *addressbook_find_datasource
305 (GtkCTreeNode *node );
307 static AddressBookFile *addressbook_get_book_file(void);
309 static GtkCTreeNode *addressbook_node_add_folder
310 (GtkCTreeNode *node,
311 AddressDataSource *ds,
312 ItemFolder *itemFolder,
313 AddressObjectType otype);
314 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
315 AddressDataSource *ds,
316 ItemGroup *itemGroup);
317 static void addressbook_tree_remove_children (GtkCTree *ctree,
318 GtkCTreeNode *parent);
319 static void addressbook_move_nodes_up (GtkCTree *ctree,
320 GtkCTreeNode *node);
321 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
322 ItemGroup *group);
323 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
324 GdkEventKey *event,
325 gpointer data);
326 static gint addressbook_treenode_compare_func (GtkCList *clist,
327 gconstpointer ptr1,
328 gconstpointer ptr2);
329 static void addressbook_folder_load_one_person (GtkCTree *clist,
330 ItemPerson *person,
331 AddressTypeControlItem *atci,
332 AddressTypeControlItem *atciMail);
333 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
334 ItemPerson *person);
335 static void addressbook_folder_remove_one_person(GtkCTree *clist,
336 ItemPerson *person);
337 static void addressbook_folder_remove_node (GtkCTree *clist,
338 GtkCTreeNode *node);
340 /* LUT's and IF stuff */
341 static void addressbook_free_treenode ( gpointer data );
342 AddressTypeControlItem *addrbookctl_lookup (gint ot);
343 AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
345 void addrbookctl_build_map (GtkWidget *window);
346 void addrbookctl_build_iflist (void);
347 AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
348 void addrbookctl_build_ifselect (void);
350 static void addrbookctl_free_interface (AdapterInterface *adapter);
351 static void addrbookctl_free_datasource (AdapterDSource *adapter);
352 static void addrbookctl_free_folder (AdapterFolder *adapter);
353 static void addrbookctl_free_group (AdapterGroup *adapter);
355 static void addressbook_list_select_clear ( void );
356 static void addressbook_list_select_add ( AddrItemObject *aio,
357 AddressDataSource *ds );
358 static void addressbook_list_select_remove ( AddrItemObject *aio );
360 static void addressbook_import_ldif_cb ( void );
361 static void addressbook_import_mutt_cb ( void );
362 static void addressbook_import_pine_cb ( void );
363 static void addressbook_export_html_cb ( void );
364 static void addressbook_export_ldif_cb ( void );
365 static void addressbook_select_all_cb ( void );
366 static void addressbook_clip_cut_cb ( void );
367 static void addressbook_clip_copy_cb ( void );
368 static void addressbook_clip_paste_cb ( void );
369 static void addressbook_treenode_cut_cb ( void );
370 static void addressbook_treenode_copy_cb ( void );
371 static void addressbook_treenode_paste_cb ( void );
373 static void addressbook_mail_to_cb ( void );
375 #ifdef USE_LDAP
376 static void addressbook_browse_entry_cb ( void );
377 #endif
378 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
380 static void addressbook_start_drag(GtkWidget *widget, gint button,
381 GdkEvent *event,
382 void *data);
383 static void addressbook_drag_data_get(GtkWidget *widget,
384 GdkDragContext *drag_context,
385 GtkSelectionData *selection_data,
386 guint info,
387 guint time,
388 void *data);
389 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
390 GdkDragContext *context,
391 gint x,
392 gint y,
393 guint time,
394 void *data);
395 static void addressbook_drag_leave_cb(GtkWidget *widget,
396 GdkDragContext *context,
397 guint time,
398 void *data);
399 static void addressbook_drag_received_cb(GtkWidget *widget,
400 GdkDragContext *drag_context,
401 gint x,
402 gint y,
403 GtkSelectionData *data,
404 guint info,
405 guint time,
406 void *pdata);
407 static void addressbook_list_menu_setup( void );
409 static GtkTargetEntry addressbook_drag_types[] =
411 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
414 static GtkTargetList *addressbook_target_list = NULL;
417 static GtkItemFactoryEntry addressbook_entries[] =
419 {N_("/_Book"), NULL, NULL, 0, "<Branch>"},
420 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL},
421 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL},
422 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL},
423 #ifdef USE_JPILOT
424 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL},
425 #endif
426 #ifdef USE_LDAP
427 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL},
428 #endif
429 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
430 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL},
431 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL},
432 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
433 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL},
434 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL},
435 {N_("/_Address"), NULL, NULL, 0, "<Branch>"},
436 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL},
437 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
438 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL},
439 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL},
440 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL},
441 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
442 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL},
443 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL},
444 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
445 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL},
446 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL},
447 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
448 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
449 {N_("/_Tools"), NULL, NULL, 0, "<Branch>"},
450 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL},
451 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL},
452 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL},
453 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
454 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL},
455 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL},
456 {N_("/_Help"), NULL, NULL, 0, "<Branch>"},
457 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
460 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
462 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL},
463 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL},
464 {"/---", NULL, NULL, 0, "<Separator>"},
465 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL},
466 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
467 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
468 {"/---", NULL, NULL, 0, "<Separator>"},
469 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL},
470 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL},
471 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL}
474 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
476 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL},
477 {"/---", NULL, NULL, 0, "<Separator>"},
478 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
479 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
480 {"/---", NULL, NULL, 0, "<Separator>"},
481 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
482 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
483 {"/---", NULL, NULL, 0, "<Separator>"},
484 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL},
485 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL},
486 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL},
487 {"/---", NULL, NULL, 0, "<Separator>"},
488 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},*/
489 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
490 #ifdef USE_LDAP
491 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL},
492 #endif
496 * Structure of error message table.
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
499 struct _ErrMsgTableEntry {
500 gint code;
501 gchar *description;
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") },
522 { 0, NULL }
525 #ifdef USE_LDAP
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 TLS connection") },
540 { 0, NULL }
542 #endif
545 * Lookup message for specified error code.
546 * \param lut Lookup table.
547 * \param code Code to lookup.
548 * \return Description associated to code.
550 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
551 gchar *desc = NULL;
552 ErrMsgTableEntry entry;
553 gint i;
555 for( i = 0; ; i++ ) {
556 entry = lut[ i ];
557 if( entry.description == NULL ) break;
558 if( entry.code == code ) {
559 desc = entry.description;
560 break;
563 if( ! desc ) {
564 desc = _errMsgUnknown_;
566 return desc;
569 static gboolean lastCanLookup = FALSE;
571 void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
573 if (add_and_delete) {
574 gtk_widget_show(addrbook.edit_btn);
575 gtk_widget_show(addrbook.del_btn);
576 gtk_widget_show(addrbook.reg_btn);
577 } else {
578 gtk_widget_hide(addrbook.edit_btn);
579 gtk_widget_hide(addrbook.del_btn);
580 gtk_widget_hide(addrbook.reg_btn);
583 if (lookup) {
584 gtk_widget_show(addrbook.lup_btn);
585 gtk_widget_show(addrbook.entry);
586 gtk_widget_show(addrbook.label);
587 } else {
588 gtk_widget_hide(addrbook.lup_btn);
589 gtk_widget_hide(addrbook.entry);
590 gtk_widget_hide(addrbook.label);
593 lastCanLookup = lookup;
595 if (mail_ops) {
596 gtk_widget_show(addrbook.to_btn);
597 gtk_widget_show(addrbook.cc_btn);
598 gtk_widget_show(addrbook.bcc_btn);
599 } else {
600 gtk_widget_hide(addrbook.to_btn);
601 gtk_widget_hide(addrbook.cc_btn);
602 gtk_widget_hide(addrbook.bcc_btn);
606 void addressbook_open(Compose *target)
608 /* Initialize all static members */
609 if( _clipBoard_ == NULL ) {
610 _clipBoard_ = addrclip_create();
612 if( _addressIndex_ != NULL ) {
613 addrclip_set_index( _clipBoard_, _addressIndex_ );
615 if( _addressSelect_ == NULL ) {
616 _addressSelect_ = addrselect_list_create();
618 if (!addrbook.window) {
619 addressbook_read_file();
620 addressbook_create();
621 addressbook_load_tree();
622 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
623 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
625 else {
626 gtk_widget_hide(addrbook.window);
629 gtk_widget_show_all(addrbook.window);
630 if (!prefs_common.addressbook_use_editaddress_dialog)
631 addressbook_edit_person_widgetset_hide();
633 address_completion_start(addrbook.window);
635 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
636 addressbook_set_target_compose(target);
640 * Destroy addressbook.
642 void addressbook_destroy( void ) {
643 /* Free up address stuff */
644 if( _addressSelect_ != NULL ) {
645 addrselect_list_free( _addressSelect_ );
647 if( _clipBoard_ != NULL ) {
648 addrclip_free( _clipBoard_ );
650 if( _addressIndex_ != NULL ) {
651 addrindex_free_index( _addressIndex_ );
652 addrindex_teardown();
654 _addressSelect_ = NULL;
655 _clipBoard_ = NULL;
656 _addressIndex_ = NULL;
659 void addressbook_set_target_compose(Compose *target)
661 addrbook.target_compose = target;
662 addressbook_button_set_sensitive();
665 Compose *addressbook_get_target_compose(void)
667 return addrbook.target_compose;
671 * Refresh addressbook and save to file(s).
673 void addressbook_refresh( void )
675 if (addrbook.window) {
676 if (addrbook.treeSelected) {
677 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
678 addrbook.treeSelected);
679 addressbook_set_clist(
680 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
681 addrbook.treeSelected),
682 TRUE);
686 addressbook_export_to_file();
689 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
691 if (event && event->keyval == GDK_Escape)
692 addressbook_close();
693 else if (event && event->keyval == GDK_Delete) {
694 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
695 if ( /* address_index_has_focus || */ address_list_has_focus )
696 addressbook_del_clicked(NULL, NULL);
698 return FALSE;
702 *\brief Save Gtk object size to prefs dataset
704 static void addressbook_size_allocate_cb(GtkWidget *widget,
705 GtkAllocation *allocation)
707 g_return_if_fail(allocation != NULL);
709 prefs_common.addressbookwin_width = allocation->width;
710 prefs_common.addressbookwin_height = allocation->height;
713 static gint sort_column_number = 0;
714 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
716 static gint list_case_sort(
717 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
719 GtkCListRow *row1 = (GtkCListRow *) ptr1;
720 GtkCListRow *row2 = (GtkCListRow *) ptr2;
721 gchar *name1 = NULL, *name2 = NULL;
722 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
723 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
725 if( aio1->type == aio2->type ) {
726 if( row1 )
727 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
728 if( row2 )
729 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
730 if( ! name1 ) return ( name2 != NULL );
731 if( ! name2 ) return -1;
732 return strcasecmp( name1, name2 );
733 } else {
734 /* Order groups before person */
735 if( aio1->type == ITEMTYPE_GROUP ) {
736 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
737 } else if( aio2->type == ITEMTYPE_GROUP ) {
738 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
740 return 0;
744 static void addressbook_sort_list(GtkCList *clist, const gint col,
745 const GtkSortType sort_type)
747 gint pos;
748 GtkWidget *hbox, *label, *arrow;
750 sort_column_number = col;
751 sort_column_type = sort_type;
752 gtk_clist_set_compare_func(clist, list_case_sort);
753 gtk_clist_set_sort_type(clist, sort_type);
754 gtk_clist_set_sort_column(clist, col);
756 gtk_clist_freeze(clist);
757 gtk_clist_sort(clist);
759 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
760 hbox = gtk_hbox_new(FALSE, 4);
761 label = gtk_label_new(gettext(list_titles[pos]));
762 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
764 if(pos == col) {
765 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
766 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
767 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
770 gtk_widget_show_all(hbox);
771 gtk_clist_set_column_widget(clist, pos, hbox);
774 gtk_clist_thaw(clist);
777 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
779 static GtkSortType sort_type = GTK_SORT_ASCENDING;
781 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
782 GTK_SORT_ASCENDING;
783 addressbook_sort_list(clist, COL_NAME, sort_type);
786 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
788 static GtkSortType sort_type = GTK_SORT_ASCENDING;
790 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
791 GTK_SORT_ASCENDING;
792 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
795 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
797 static GtkSortType sort_type = GTK_SORT_ASCENDING;
799 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
800 GTK_SORT_ASCENDING;
801 addressbook_sort_list(clist, COL_REMARKS, sort_type);
804 static void addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
805 gpointer data)
807 address_index_has_focus = TRUE;
810 static void addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
811 gpointer data)
813 address_index_has_focus = FALSE;
816 static void addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
817 gpointer data)
819 address_list_has_focus = TRUE;
822 static void addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
823 gpointer data)
825 address_list_has_focus = FALSE;
829 * Create the address book widgets. The address book contains two CTree widgets: the
830 * address index tree on the left and the address list on the right.
832 * The address index tree displays a hierarchy of interfaces and groups. Each node in
833 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
834 * data sources and folder objects.
836 * The address list displays group, person and email objects. These items are linked
837 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
838 * sources.
840 * In the tradition of MVC architecture, the data stores have been separated from the
841 * GUI components. The addrindex.c file provides the interface to all data stores.
843 static void addressbook_create(void)
845 GtkWidget *window;
846 GtkWidget *vbox;
847 GtkWidget *menubar;
848 GtkWidget *vbox2;
849 GtkWidget *ctree_swin;
850 GtkWidget *ctree;
851 GtkWidget *editaddress_vbox;
852 GtkWidget *clist_vbox;
853 GtkWidget *clist_swin;
854 GtkWidget *clist;
855 GtkWidget *hpaned;
856 GtkWidget *vpaned;
857 GtkWidget *hbox;
858 GtkWidget *label;
859 GtkWidget *entry;
860 GtkWidget *statusbar;
861 GtkWidget *hbbox;
862 GtkWidget *hsbox;
863 GtkWidget *help_btn;
864 GtkWidget *del_btn;
865 GtkWidget *edit_btn;
866 GtkWidget *reg_btn;
867 GtkWidget *lup_btn;
868 GtkWidget *to_btn;
869 GtkWidget *cc_btn;
870 GtkWidget *bcc_btn;
871 GtkWidget *close_btn;
872 GtkWidget *tree_popup;
873 GtkWidget *list_popup;
874 GtkItemFactory *tree_factory;
875 GtkItemFactory *list_factory;
876 GtkItemFactory *menu_factory;
877 gint n_entries;
878 GList *nodeIf;
880 gchar *index_titles[N_INDEX_COLS];
881 gchar *text;
882 gint i;
884 static GdkGeometry geometry;
886 debug_print("Creating addressbook window...\n");
888 index_titles[COL_SOURCES] = _("Sources");
890 /* Address book window */
891 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
892 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
893 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
894 gtk_widget_realize(window);
896 g_signal_connect(G_OBJECT(window), "delete_event",
897 G_CALLBACK(addressbook_close), NULL);
898 g_signal_connect(G_OBJECT(window), "size_allocate",
899 G_CALLBACK(addressbook_size_allocate_cb), NULL);
900 g_signal_connect(G_OBJECT(window), "key_press_event",
901 G_CALLBACK(key_pressed), NULL);
902 MANAGE_WINDOW_SIGNALS_CONNECT(window);
904 vbox = gtk_vbox_new(FALSE, 0);
905 gtk_container_add(GTK_CONTAINER(window), vbox);
907 /* Menu bar */
908 n_entries = sizeof(addressbook_entries) /
909 sizeof(addressbook_entries[0]);
910 menubar = menubar_create(window, addressbook_entries, n_entries,
911 "<AddressBook>", NULL);
912 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
913 menu_factory = gtk_item_factory_from_widget(menubar);
915 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
916 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
917 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
919 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
920 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
921 GTK_POLICY_AUTOMATIC,
922 GTK_POLICY_AUTOMATIC);
923 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
925 /* Address index */
926 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
927 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
928 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
929 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
930 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
931 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
932 GTK_CTREE_EXPANDER_SQUARE);
933 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
934 gtk_clist_set_compare_func(GTK_CLIST(ctree),
935 addressbook_treenode_compare_func);
937 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
938 G_CALLBACK(addressbook_tree_selected), NULL);
939 g_signal_connect(G_OBJECT(ctree), "button_press_event",
940 G_CALLBACK(addressbook_tree_button_pressed),
941 NULL);
942 g_signal_connect(G_OBJECT(ctree), "button_release_event",
943 G_CALLBACK(addressbook_tree_button_released),
944 NULL);
945 /* TEMPORARY */
946 g_signal_connect(G_OBJECT(ctree), "select_row",
947 G_CALLBACK(addressbook_select_row_tree), NULL);
949 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
950 addressbook_drag_types, 1,
951 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
952 g_signal_connect(G_OBJECT(ctree), "drag_motion",
953 G_CALLBACK(addressbook_drag_motion_cb),
954 ctree);
955 g_signal_connect(G_OBJECT(ctree), "drag_leave",
956 G_CALLBACK(addressbook_drag_leave_cb),
957 ctree);
958 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
959 G_CALLBACK(addressbook_drag_received_cb),
960 ctree);
961 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
962 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
963 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
964 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
966 clist_vbox = gtk_vbox_new(FALSE, 4);
968 clist_swin = gtk_scrolled_window_new(NULL, NULL);
969 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
970 GTK_POLICY_AUTOMATIC,
971 GTK_POLICY_AUTOMATIC);
972 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
974 /* Address list */
975 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
976 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
977 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
978 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
979 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
980 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
981 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
982 COL_NAME_WIDTH);
983 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
984 COL_ADDRESS_WIDTH);
985 gtk_widget_set_size_request(clist, -1, 80);
987 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
988 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
989 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
990 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
991 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
992 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
993 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
994 g_signal_connect(G_OBJECT(clist), "focus_in_event",
995 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
996 g_signal_connect(G_OBJECT(clist), "focus_out_event",
997 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
999 for (i = 0; i < N_LIST_COLS; i++)
1000 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1001 GTK_CAN_FOCUS);
1003 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1004 G_CALLBACK(addressbook_list_row_selected), NULL);
1005 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1006 G_CALLBACK(addressbook_list_row_unselected), NULL);
1007 g_signal_connect(G_OBJECT(clist), "button_press_event",
1008 G_CALLBACK(addressbook_list_button_pressed),
1009 NULL);
1010 g_signal_connect(G_OBJECT(clist), "button_release_event",
1011 G_CALLBACK(addressbook_list_button_released),
1012 NULL);
1013 g_signal_connect(G_OBJECT(clist), "tree_expand",
1014 G_CALLBACK(addressbook_person_expand_node), NULL );
1015 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1016 G_CALLBACK(addressbook_person_collapse_node), NULL );
1017 g_signal_connect(G_OBJECT(clist), "start_drag",
1018 G_CALLBACK(addressbook_start_drag), NULL);
1019 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1020 G_CALLBACK(addressbook_drag_data_get), NULL);
1021 hbox = gtk_hbox_new(FALSE, 4);
1022 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1024 label = gtk_label_new(_("Lookup name:"));
1025 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1027 entry = gtk_entry_new();
1028 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1030 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1032 g_signal_connect(G_OBJECT(entry), "key_press_event",
1033 G_CALLBACK(addressbook_entry_key_pressed),
1034 NULL);
1036 if (!prefs_common.addressbook_use_editaddress_dialog) {
1037 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1038 vpaned = gtk_vpaned_new();
1039 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1040 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1041 } else {
1042 vpaned = NULL;
1043 editaddress_vbox = NULL;
1045 hpaned = gtk_hpaned_new();
1046 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1047 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1048 if (prefs_common.addressbook_use_editaddress_dialog)
1049 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1050 else
1051 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1053 /* Status bar */
1054 hsbox = gtk_hbox_new(FALSE, 0);
1055 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1056 statusbar = gtk_statusbar_new();
1057 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1059 /* Button panel */
1060 hbbox = gtk_hbutton_box_new();
1061 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1062 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1063 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1064 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1066 gtkut_stock_button_add_help(hbbox, &help_btn);
1068 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1069 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1070 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1071 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1072 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1073 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1074 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1075 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1076 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1079 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1080 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1081 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1083 g_signal_connect(G_OBJECT(help_btn), "clicked",
1084 G_CALLBACK(manual_open_with_anchor_cb),
1085 MANUAL_ANCHOR_ADDRBOOK);
1087 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1088 G_CALLBACK(addressbook_edit_clicked), NULL);
1089 g_signal_connect(G_OBJECT(del_btn), "clicked",
1090 G_CALLBACK(addressbook_del_clicked), NULL);
1091 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1092 G_CALLBACK(addressbook_reg_clicked), NULL);
1093 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1094 G_CALLBACK(addressbook_lup_clicked), NULL);
1096 to_btn = gtk_button_new_with_label
1097 (prefs_common.trans_hdr ? _("To:") : "To:");
1098 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1099 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1100 cc_btn = gtk_button_new_with_label
1101 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
1102 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1103 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1104 bcc_btn = gtk_button_new_with_label
1105 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
1106 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1107 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1109 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1110 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1111 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1113 g_signal_connect(G_OBJECT(to_btn), "clicked",
1114 G_CALLBACK(addressbook_to_clicked),
1115 GINT_TO_POINTER(COMPOSE_TO));
1116 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1117 G_CALLBACK(addressbook_to_clicked),
1118 GINT_TO_POINTER(COMPOSE_CC));
1119 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1120 G_CALLBACK(addressbook_to_clicked),
1121 GINT_TO_POINTER(COMPOSE_BCC));
1122 g_signal_connect(G_OBJECT(close_btn), "clicked",
1123 G_CALLBACK(addressbook_close_clicked), NULL);
1125 /* Build icons for interface */
1126 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1127 &interfacexpm, &interfacexpmmask );
1129 /* Build control tables */
1130 addrbookctl_build_map(window);
1131 addrbookctl_build_iflist();
1132 addrbookctl_build_ifselect();
1134 addrbook.clist = NULL;
1136 /* Add each interface into the tree as a root level folder */
1137 nodeIf = _addressInterfaceList_;
1138 while( nodeIf ) {
1139 AdapterInterface *adapter = nodeIf->data;
1140 AddressInterface *iface = adapter->interface;
1141 nodeIf = g_list_next(nodeIf);
1143 if(iface->useInterface) {
1144 AddressTypeControlItem *atci = adapter->atci;
1145 text = atci->displayName;
1146 adapter->treeNode =
1147 gtk_sctree_insert_node( GTK_CTREE(ctree),
1148 NULL, NULL, &text, FOLDER_SPACING,
1149 interfacexpm, interfacexpmmask,
1150 interfacexpm, interfacexpmmask,
1151 FALSE, FALSE );
1152 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1153 gtk_ctree_node_set_row_data_full(
1154 GTK_CTREE(ctree), adapter->treeNode, adapter,
1155 addressbook_free_treenode );
1159 /* Popup menu */
1160 n_entries = sizeof(addressbook_tree_popup_entries) /
1161 sizeof(addressbook_tree_popup_entries[0]);
1162 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1163 n_entries,
1164 "<AddressBookTree>", &tree_factory,
1165 NULL);
1166 n_entries = sizeof(addressbook_list_popup_entries) /
1167 sizeof(addressbook_list_popup_entries[0]);
1168 list_popup = menu_create_items(addressbook_list_popup_entries,
1169 n_entries,
1170 "<AddressBookList>", &list_factory,
1171 NULL);
1173 addrbook.window = window;
1174 addrbook.menubar = menubar;
1175 addrbook.ctree = ctree;
1176 addrbook.ctree_swin
1177 = ctree_swin;
1178 addrbook.editaddress_vbox = editaddress_vbox;
1179 addrbook.clist = clist;
1180 addrbook.label = label;
1181 addrbook.entry = entry;
1182 addrbook.statusbar = statusbar;
1183 addrbook.status_cid = gtk_statusbar_get_context_id(
1184 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1186 addrbook.help_btn = help_btn;
1187 addrbook.edit_btn = edit_btn;
1188 addrbook.del_btn = del_btn;
1189 addrbook.reg_btn = reg_btn;
1190 addrbook.lup_btn = lup_btn;
1191 addrbook.to_btn = to_btn;
1192 addrbook.cc_btn = cc_btn;
1193 addrbook.bcc_btn = bcc_btn;
1195 addrbook.tree_popup = tree_popup;
1196 addrbook.list_popup = list_popup;
1197 addrbook.tree_factory = tree_factory;
1198 addrbook.list_factory = list_factory;
1199 addrbook.menu_factory = menu_factory;
1201 addrbook.listSelected = NULL;
1203 if (!geometry.min_height) {
1204 geometry.min_width = ADDRESSBOOK_WIDTH;
1205 geometry.min_height = ADDRESSBOOK_HEIGHT;
1208 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1209 GDK_HINT_MIN_SIZE);
1210 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1211 prefs_common.addressbookwin_height);
1213 gtk_widget_show_all(window);
1217 * Close address book window and save to file(s).
1219 static gint addressbook_close( void ) {
1220 address_completion_end(addrbook.window);
1221 if (!prefs_common.addressbook_use_editaddress_dialog)
1222 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1223 gtk_widget_hide(addrbook.window);
1224 addressbook_export_to_file();
1225 return TRUE;
1229 * Display message in status line.
1230 * \param msg Message to display.
1232 static void addressbook_status_show( gchar *msg ) {
1233 if( addrbook.statusbar != NULL ) {
1234 gtk_statusbar_pop(
1235 GTK_STATUSBAR(addrbook.statusbar),
1236 addrbook.status_cid );
1237 if( msg ) {
1238 gtk_statusbar_push(
1239 GTK_STATUSBAR(addrbook.statusbar),
1240 addrbook.status_cid, msg );
1245 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1246 *addressbook_msgbuf = '\0';
1247 if( ds ) {
1248 gchar *name;
1250 name = addrindex_ds_get_name( ds );
1251 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1252 "%s: %s", name, msg );
1254 else {
1255 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1256 "%s", msg );
1258 addressbook_status_show( addressbook_msgbuf );
1261 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1262 gint retVal;
1263 gchar *name;
1264 gchar *desc;
1265 *addressbook_msgbuf = '\0';
1266 if( ds ) {
1267 name = addrindex_ds_get_name( ds );
1268 retVal = addrindex_ds_get_status_code( ds );
1269 if( retVal == MGU_SUCCESS ) {
1270 g_snprintf( addressbook_msgbuf,
1271 sizeof(addressbook_msgbuf), "%s", name );
1273 else {
1274 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1275 g_snprintf( addressbook_msgbuf,
1276 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1279 addressbook_status_show( addressbook_msgbuf );
1282 static void addressbook_button_set_sensitive(void)
1284 gboolean to_sens = FALSE;
1285 gboolean cc_sens = FALSE;
1286 gboolean bcc_sens = FALSE;
1288 if (!addrbook.window) return;
1290 if (addrbook.target_compose) {
1291 to_sens = TRUE;
1292 cc_sens = TRUE;
1293 #ifndef CLAWS
1294 if (addrbook.target_compose->use_bcc)
1295 #endif
1296 bcc_sens = TRUE;
1299 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1300 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1301 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1304 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1306 addressbook_edit_address_cb(NULL, 0, NULL);
1310 * Delete one or more objects from address list.
1312 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1314 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1315 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1316 AddressObject *pobj;
1317 AdapterDSource *ads = NULL;
1318 GtkCTreeNode *nodeList;
1319 gboolean procFlag;
1320 AlertValue aval;
1321 AddressBookFile *abf = NULL;
1322 AddressDataSource *ds = NULL;
1323 AddressInterface *iface;
1324 AddrItemObject *aio;
1325 AddrSelectItem *item;
1326 GList *list, *node;
1327 gboolean refreshList = FALSE;
1329 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1330 g_return_if_fail(pobj != NULL);
1332 /* Test whether anything selected for deletion */
1333 nodeList = addrbook.listSelected;
1335 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1336 if( aio == NULL) return;
1337 ds = addressbook_find_datasource( addrbook.treeSelected );
1338 if( ds == NULL ) return;
1340 /* Test for read only */
1341 iface = ds->interface;
1342 if( iface->readOnly ) {
1343 alertpanel( _("Delete address(es)"),
1344 _("This address data is readonly and cannot be deleted."),
1345 GTK_STOCK_CLOSE, NULL, NULL );
1346 return;
1349 /* Test whether Ok to proceed */
1350 procFlag = FALSE;
1351 if( pobj->type == ADDR_DATASOURCE ) {
1352 ads = ADAPTER_DSOURCE(pobj);
1353 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1355 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1356 procFlag = TRUE;
1358 else if( pobj->type == ADDR_ITEM_GROUP ) {
1359 procFlag = TRUE;
1361 if( ! procFlag ) return;
1362 abf = ds->rawDataSource;
1363 if( abf == NULL ) return;
1366 /* Process deletions */
1367 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1368 gboolean group_delete = TRUE;
1369 /* Items inside folders */
1370 list = addrselect_get_list( _addressSelect_ );
1371 /* Confirm deletion */
1372 node = list;
1373 while( node ) {
1374 item = node->data;
1375 node = g_list_next( node );
1376 aio = ( AddrItemObject * ) item->addressItem;
1377 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1378 group_delete = FALSE;
1379 break;
1382 if (group_delete) {
1383 aval = alertpanel( _("Delete group"),
1384 _("Really delete the group(s)?\n"
1385 "The addresses it contains will not be lost."),
1386 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1387 if( aval != G_ALERTALTERNATE ) return;
1388 } else {
1389 aval = alertpanel( _("Delete address(es)"),
1390 _("Really delete the address(es)?"),
1391 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1392 if( aval != G_ALERTALTERNATE ) return;
1395 node = list;
1396 while( node ) {
1397 item = node->data;
1398 node = g_list_next( node );
1399 aio = ( AddrItemObject * ) item->addressItem;
1400 if( aio->type == ADDR_ITEM_GROUP ) {
1401 ItemGroup *item = ( ItemGroup * ) aio;
1402 GtkCTreeNode *nd = NULL;
1404 nd = addressbook_find_group_node( addrbook.opened, item );
1405 item = addrbook_remove_group( abf, item );
1406 if( item ) {
1407 addritem_free_item_group( item );
1409 /* Remove group from parent node */
1410 gtk_ctree_remove_node( ctree, nd );
1411 refreshList = TRUE;
1413 else if( aio->type == ADDR_ITEM_PERSON ) {
1414 ItemPerson *item = ( ItemPerson * ) aio;
1415 addressbook_folder_remove_one_person( clist, item );
1416 if (pobj->type == ADDR_ITEM_FOLDER)
1417 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1418 item = addrbook_remove_person( abf, item );
1419 if( item ) {
1420 addritem_free_item_person( item );
1423 else if( aio->type == ADDR_ITEM_EMAIL ) {
1424 ItemEMail *item = ( ItemEMail * ) aio;
1425 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1426 item = addrbook_person_remove_email( abf, person, item );
1427 if( item ) {
1428 addrcache_remove_email(abf->addressCache, item);
1429 addritem_free_item_email( item );
1431 addressbook_folder_refresh_one_person( clist, person );
1434 g_list_free( list );
1435 addressbook_list_select_clear();
1436 if( refreshList ) {
1437 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1438 addressbook_set_clist(
1439 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1440 addrbook.opened),
1441 TRUE);
1443 addrbook_set_dirty(abf, TRUE);
1444 addressbook_export_to_file();
1445 addressbook_list_menu_setup();
1446 return;
1448 else if( pobj->type == ADDR_ITEM_GROUP ) {
1449 /* Items inside groups */
1450 list = addrselect_get_list( _addressSelect_ );
1451 node = list;
1452 while( node ) {
1453 item = node->data;
1454 node = g_list_next( node );
1455 aio = ( AddrItemObject * ) item->addressItem;
1456 if( aio->type == ADDR_ITEM_EMAIL ) {
1457 ItemEMail *item = ( ItemEMail * ) aio;
1458 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1459 item = addrbook_person_remove_email( abf, person, item );
1460 if( item ) {
1461 addritem_free_item_email( item );
1465 g_list_free( list );
1466 addressbook_list_select_clear();
1467 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1468 addressbook_set_clist(
1469 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1470 addrbook.opened),
1471 TRUE);
1473 addrbook_set_dirty(abf, TRUE);
1474 addressbook_export_to_file();
1475 addressbook_list_menu_setup();
1476 return;
1479 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1480 gtk_ctree_remove_node( clist, nodeList );
1484 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1486 addressbook_new_address_cb( NULL, 0, NULL );
1489 gchar *addressbook_format_address( AddrItemObject * aio ) {
1490 gchar *buf = NULL;
1491 gchar *name = NULL;
1492 gchar *address = NULL;
1494 if( aio->type == ADDR_ITEM_EMAIL ) {
1495 ItemPerson *person = NULL;
1496 ItemEMail *email = ( ItemEMail * ) aio;
1498 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1499 if( email->address ) {
1500 if( ADDRITEM_NAME(email) ) {
1501 name = ADDRITEM_NAME(email);
1502 if( *name == '\0' ) {
1503 name = ADDRITEM_NAME(person);
1506 else if( ADDRITEM_NAME(person) ) {
1507 name = ADDRITEM_NAME(person);
1509 else {
1510 buf = g_strdup( email->address );
1512 address = email->address;
1515 else if( aio->type == ADDR_ITEM_PERSON ) {
1516 ItemPerson *person = ( ItemPerson * ) aio;
1517 GList *node = person->listEMail;
1519 name = ADDRITEM_NAME(person);
1520 if( node ) {
1521 ItemEMail *email = ( ItemEMail * ) node->data;
1522 address = email->address;
1525 if( address ) {
1526 if( name && name[0] != '\0' ) {
1527 if( strchr_with_skip_quote( name, '"', ',' ) )
1528 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1529 else
1530 buf = g_strdup_printf( "%s <%s>", name, address );
1532 else {
1533 buf = g_strdup( address );
1537 return buf;
1540 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1542 GList *list, *node;
1543 Compose *compose;
1544 AddrSelectItem *item;
1545 AddrItemObject *aio;
1546 gchar *addr;
1548 compose = addrbook.target_compose;
1549 if( ! compose ) return;
1551 /* Nothing selected, but maybe there is something in text entry */
1552 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1553 if ( addr ) {
1554 compose_entry_append(
1555 compose, addr, (ComposeEntryType)data );
1558 /* Select from address list */
1559 list = addrselect_get_list( _addressSelect_ );
1560 node = list;
1561 if (node) {
1562 while( node ) {
1563 item = node->data;
1564 node = g_list_next( node );
1565 aio = item->addressItem;
1566 if( aio->type == ADDR_ITEM_PERSON ||
1567 aio->type == ADDR_ITEM_EMAIL ) {
1568 addr = addressbook_format_address( aio );
1569 compose_entry_append(
1570 compose, addr, (ComposeEntryType) data );
1571 g_free( addr );
1573 else if( aio->type == ADDR_ITEM_GROUP ) {
1574 ItemGroup *group = ( ItemGroup * ) aio;
1575 GList *nodeMail = group->listEMail;
1576 while( nodeMail ) {
1577 ItemEMail *email = nodeMail->data;
1579 addr = addressbook_format_address(
1580 ( AddrItemObject * ) email );
1581 compose_entry_append(
1582 compose, addr, (ComposeEntryType) data );
1583 g_free( addr );
1584 nodeMail = g_list_next( nodeMail );
1588 } else {
1589 AddressObject *obj = NULL;
1591 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1593 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1594 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1595 GList *nodeMail = itemGroup->listEMail;
1596 while( nodeMail ) {
1597 ItemEMail *email = nodeMail->data;
1599 addr = addressbook_format_address(
1600 ( AddrItemObject * ) email );
1601 compose_entry_append(
1602 compose, addr, (ComposeEntryType) data );
1603 g_free( addr );
1604 nodeMail = g_list_next( nodeMail );
1608 g_list_free( list );
1611 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1612 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1613 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1614 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1616 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1617 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1618 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1619 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1621 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1622 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1623 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1624 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1625 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1626 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1629 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1630 gboolean canEdit = FALSE;
1631 gboolean canDelete = TRUE;
1632 gboolean canAdd = FALSE;
1633 gboolean canEditTr = TRUE;
1634 gboolean editAddress = FALSE;
1635 gboolean canExport = TRUE;
1636 AddressTypeControlItem *atci = NULL;
1637 AddressDataSource *ds = NULL;
1638 AddressInterface *iface = NULL;
1640 if( obj == NULL ) return;
1641 if( obj->type == ADDR_INTERFACE ) {
1642 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1643 iface = adapter->interface;
1644 if( iface ) {
1645 if( iface->haveLibrary ) {
1646 /* Enable appropriate File / New command */
1647 atci = adapter->atci;
1648 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1651 canEditTr = canExport = FALSE;
1653 else if( obj->type == ADDR_DATASOURCE ) {
1654 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1655 ds = ads->dataSource;
1656 iface = ds->interface;
1657 if( ! iface->readOnly ) {
1658 canAdd = canEdit = editAddress = canDelete = TRUE;
1660 if( ! iface->haveLibrary ) {
1661 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1664 else if( obj->type == ADDR_ITEM_FOLDER ) {
1665 ds = addressbook_find_datasource( addrbook.treeSelected );
1666 if( ds ) {
1667 iface = ds->interface;
1668 if( iface->readOnly ) {
1669 canEditTr = FALSE;
1670 canDelete = FALSE;
1672 else {
1673 canAdd = editAddress = TRUE;
1677 else if( obj->type == ADDR_ITEM_GROUP ) {
1678 ds = addressbook_find_datasource( addrbook.treeSelected );
1679 if( ds ) {
1680 iface = ds->interface;
1681 if( ! iface->readOnly ) {
1682 editAddress = TRUE;
1687 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1689 /* Enable add */
1690 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1691 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1692 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1693 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1695 /* Enable edit */
1696 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1697 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1698 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1699 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1701 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1702 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1704 /* Export data */
1705 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1706 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1709 static void addressbook_list_menu_setup( void );
1712 * Address book tree callback function that responds to selection of tree
1713 * items.
1715 * \param ctree Tree widget.
1716 * \param node Node that was selected.
1717 * \param column Column number where selected occurred.
1718 * \param data Pointer to user data.
1720 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1721 gint column, gpointer data)
1723 AddressObject *obj = NULL;
1724 AdapterDSource *ads = NULL;
1725 AddressDataSource *ds = NULL;
1726 ItemFolder *rootFolder = NULL;
1727 AddressObjectType aot;
1729 addrbook.treeSelected = node;
1730 addrbook.listSelected = NULL;
1731 addressbook_status_show( "" );
1732 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1734 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1735 if( obj == NULL ) {
1736 addressbook_set_clist(NULL, TRUE);
1737 return;
1739 addrbook.opened = node;
1741 if( obj->type == ADDR_DATASOURCE ) {
1742 /* Read from file */
1743 static gboolean tVal = TRUE;
1745 ads = ADAPTER_DSOURCE(obj);
1746 if( ads == NULL ) return;
1747 ds = ads->dataSource;
1748 if( ds == NULL ) return;
1750 if( addrindex_ds_get_modify_flag( ds ) ) {
1751 addrindex_ds_read_data( ds );
1754 if( ! addrindex_ds_get_read_flag( ds ) ) {
1755 addrindex_ds_read_data( ds );
1757 addressbook_ds_show_message( ds );
1759 if( ! addrindex_ds_get_access_flag( ds ) ) {
1760 /* Remove existing folders and groups */
1761 gtk_clist_freeze( GTK_CLIST(ctree) );
1762 addressbook_tree_remove_children( ctree, node );
1763 gtk_clist_thaw( GTK_CLIST(ctree) );
1765 /* Load folders into the tree */
1766 rootFolder = addrindex_ds_get_root_folder( ds );
1767 if( ds->type == ADDR_IF_JPILOT ) {
1768 aot = ADDR_CATEGORY;
1770 else if( ds->type == ADDR_IF_LDAP ) {
1771 aot = ADDR_LDAP_QUERY;
1773 else {
1774 aot = ADDR_ITEM_FOLDER;
1776 addressbook_node_add_folder( node, ds, rootFolder, aot );
1777 addrindex_ds_set_access_flag( ds, &tVal );
1778 gtk_ctree_expand( ctree, node );
1780 } else {
1781 addressbook_set_clist(NULL, TRUE);
1784 /* Update address list */
1785 g_signal_handlers_block_by_func
1786 (G_OBJECT(ctree),
1787 G_CALLBACK(addressbook_tree_selected), NULL);
1788 addressbook_set_clist( obj, FALSE );
1789 g_signal_handlers_unblock_by_func
1790 (G_OBJECT(ctree),
1791 G_CALLBACK(addressbook_tree_selected), NULL);
1792 if (!prefs_common.addressbook_use_editaddress_dialog)
1793 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1795 /* Setup main menu selections */
1796 addressbook_menubar_set_sensitive( FALSE );
1797 addressbook_list_menu_setup();
1798 addressbook_menuitem_set_sensitive( obj, node );
1800 addressbook_list_select_clear();
1801 addressbook_list_menu_setup();
1802 return;
1806 * Setup address list popup menu items. Items are enabled or disabled as
1807 * required.
1809 static void addressbook_list_menu_setup( void ) {
1810 GtkCTree *clist = NULL;
1811 AddressObject *pobj = NULL;
1812 AddressObject *obj = NULL;
1813 AdapterDSource *ads = NULL;
1814 AddressInterface *iface = NULL;
1815 AddressDataSource *ds = NULL;
1816 gboolean canEdit = FALSE;
1817 gboolean canDelete = FALSE;
1818 gboolean canCut = FALSE;
1819 gboolean canCopy = FALSE;
1820 gboolean canPaste = FALSE;
1821 gboolean canBrowse = FALSE;
1823 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1824 if( pobj == NULL ) return;
1826 clist = GTK_CTREE(addrbook.clist);
1827 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1828 if( obj == NULL ) canEdit = FALSE;
1830 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1831 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1833 if( pobj->type == ADDR_DATASOURCE ) {
1834 /* Parent object is a data source */
1835 ads = ADAPTER_DSOURCE(pobj);
1836 ds = ads->dataSource;
1837 iface = ds->interface;
1838 if( ! iface->readOnly ) {
1839 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1840 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1841 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1842 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1843 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1844 if( obj ) canEdit = TRUE;
1846 canDelete = canEdit;
1848 else if( pobj->type != ADDR_INTERFACE ) {
1849 /* Parent object is not an interface */
1850 ds = addressbook_find_datasource( addrbook.treeSelected );
1851 iface = ds->interface;
1852 if( ! iface->readOnly ) {
1853 /* Folder or group */
1854 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1855 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1856 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1857 if( obj ) canEdit = TRUE;
1859 /* Folder */
1860 if( pobj->type == ADDR_ITEM_FOLDER ) {
1861 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1862 if( obj ) canEdit = TRUE;
1864 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1865 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1866 canDelete = canEdit;
1868 if( iface->type == ADDR_IF_LDAP ) {
1869 if( obj ) canBrowse = TRUE;
1870 canEdit = TRUE;
1871 canDelete = FALSE;
1874 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1876 /* Disable edit or browse if more than one row selected */
1877 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1878 canEdit = FALSE;
1879 canBrowse = FALSE;
1882 /* Now go finalize menu items */
1883 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1884 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1886 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1887 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1888 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1889 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1891 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1893 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1894 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1895 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1896 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1898 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1899 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1900 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1902 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1903 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1904 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1906 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1907 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1909 #ifdef USE_LDAP
1910 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1911 #endif
1914 static void addressbook_select_row_tree (GtkCTree *ctree,
1915 GtkCTreeNode *node,
1916 gint column,
1917 gpointer data)
1922 * Add list of items into tree node below specified tree node.
1923 * \param treeNode Tree node.
1924 * \param ds Data source.
1925 * \param listItems List of items.
1927 static void addressbook_treenode_add_list(
1928 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1930 GList *node;
1932 node = listItems;
1933 while( node ) {
1934 AddrItemObject *aio;
1935 GtkCTreeNode *nn;
1937 aio = node->data;
1938 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
1939 ItemGroup *group;
1941 group = ( ItemGroup * ) aio;
1942 nn = addressbook_node_add_group( treeNode, ds, group );
1944 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
1945 ItemFolder *folder;
1947 folder = ( ItemFolder * ) aio;
1948 nn = addressbook_node_add_folder(
1949 treeNode, ds, folder, ADDR_ITEM_FOLDER );
1951 node = g_list_next( node );
1955 static void addressbook_select_all_cb( void ) {
1956 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
1960 * Cut from address list widget.
1962 static void addressbook_clip_cut_cb( void ) {
1963 _clipBoard_->cutFlag = TRUE;
1964 addrclip_clear( _clipBoard_ );
1965 addrclip_add( _clipBoard_, _addressSelect_ );
1966 /* addrclip_list_show( _clipBoard_, stdout ); */
1970 * Copy from address list widget.
1972 static void addressbook_clip_copy_cb( void ) {
1973 _clipBoard_->cutFlag = FALSE;
1974 addrclip_clear( _clipBoard_ );
1975 addrclip_add( _clipBoard_, _addressSelect_ );
1976 /* addrclip_list_show( _clipBoard_, stdout ); */
1980 * Paste clipboard into address list widget.
1982 static void addressbook_clip_paste_cb( void ) {
1983 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
1984 AddressObject *pobj = NULL;
1985 AddressDataSource *ds = NULL;
1986 AddressBookFile *abf = NULL;
1987 ItemFolder *folder = NULL;
1988 GList *folderGroup = NULL;
1990 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
1991 if( ds == NULL ) return;
1992 if( addrindex_ds_get_readonly( ds ) ) {
1993 addressbook_ds_status_message(
1994 ds, _( "Cannot paste. Target address book is readonly." ) );
1995 return;
1998 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
1999 if( pobj ) {
2000 if( pobj->type == ADDR_ITEM_FOLDER ) {
2001 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2003 else if( pobj->type == ADDR_ITEM_GROUP ) {
2004 addressbook_ds_status_message(
2005 ds, _( "Cannot paste into an address group." ) );
2006 return;
2010 /* Get an address book */
2011 abf = addressbook_get_book_file();
2012 if( abf == NULL ) return;
2014 if( _clipBoard_->cutFlag ) {
2015 /* Paste/Cut */
2016 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2018 /* Remove all groups and folders in clipboard from tree node */
2019 addressbook_treenode_remove_item();
2021 /* Remove all "cut" items */
2022 addrclip_delete_item( _clipBoard_ );
2024 /* Clear clipboard - cut items??? */
2025 addrclip_clear( _clipBoard_ );
2027 else {
2028 /* Paste/Copy */
2029 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2032 /* addrclip_list_show( _clipBoard_, stdout ); */
2033 if( folderGroup ) {
2034 /* Update tree by inserting node for each folder or group */
2035 addressbook_treenode_add_list(
2036 addrbook.treeSelected, ds, folderGroup );
2037 gtk_ctree_expand( ctree, addrbook.treeSelected );
2038 g_list_free( folderGroup );
2039 folderGroup = NULL;
2042 /* Display items pasted */
2043 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2044 addressbook_set_clist(
2045 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2046 addrbook.opened),
2047 TRUE);
2053 * Add current treenode object to clipboard. Note that widget only allows
2054 * one entry from the tree list to be selected.
2056 static void addressbook_treenode_to_clipboard( void ) {
2057 AddressObject *obj = NULL;
2058 AddressDataSource *ds = NULL;
2059 AddrSelectItem *item;
2060 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2061 GtkCTreeNode *node;
2063 node = addrbook.treeSelected;
2064 if( node == NULL ) return;
2065 obj = gtk_ctree_node_get_row_data( ctree, node );
2066 if( obj == NULL ) return;
2068 ds = addressbook_find_datasource( node );
2069 if( ds == NULL ) return;
2071 item = NULL;
2072 if( obj->type == ADDR_ITEM_FOLDER ) {
2073 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2074 ItemFolder *folder = adapter->itemFolder;
2076 item = addrselect_create_node( obj );
2077 item->uid = g_strdup( ADDRITEM_ID(folder) );
2079 else if( obj->type == ADDR_ITEM_GROUP ) {
2080 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2081 ItemGroup *group = adapter->itemGroup;
2083 item = addrselect_create_node( obj );
2084 item->uid = g_strdup( ADDRITEM_ID(group) );
2086 else if( obj->type == ADDR_DATASOURCE ) {
2087 /* Data source */
2088 item = addrselect_create_node( obj );
2089 item->uid = NULL;
2092 if( item ) {
2093 /* Clear existing list and add item into list */
2094 gchar *cacheID;
2096 addressbook_list_select_clear();
2097 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2098 addrselect_list_add( _addressSelect_, item, cacheID );
2099 g_free( cacheID );
2104 * Cut from tree widget.
2106 static void addressbook_treenode_cut_cb( void ) {
2107 _clipBoard_->cutFlag = TRUE;
2108 addressbook_treenode_to_clipboard();
2109 addrclip_clear( _clipBoard_ );
2110 addrclip_add( _clipBoard_, _addressSelect_ );
2111 /* addrclip_list_show( _clipBoard_, stdout ); */
2115 * Copy from tree widget.
2117 static void addressbook_treenode_copy_cb( void ) {
2118 _clipBoard_->cutFlag = FALSE;
2119 addressbook_treenode_to_clipboard();
2120 addrclip_clear( _clipBoard_ );
2121 addrclip_add( _clipBoard_, _addressSelect_ );
2122 /* addrclip_list_show( _clipBoard_, stdout ); */
2126 * Paste clipboard into address tree widget.
2128 static void addressbook_treenode_paste_cb( void ) {
2129 addressbook_clip_paste_cb();
2133 * Clear selected entries in clipboard.
2135 static void addressbook_list_select_clear( void ) {
2136 addrselect_list_clear( _addressSelect_ );
2140 * Add specified address item to selected address list.
2141 * \param aio Address item object.
2142 * \param ds Datasource.
2144 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2145 gchar *cacheID;
2147 if( ds == NULL ) return;
2148 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2149 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2150 g_free( cacheID );
2154 * Remove specified address item from selected address list.
2155 * \param aio Address item object.
2157 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2158 addrselect_list_remove( _addressSelect_, aio );
2162 * Invoke EMail compose window with addresses in selected address list.
2164 static void addressbook_mail_to_cb( void ) {
2165 GList *listAddress;
2167 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2168 listAddress = addrselect_build_list( _addressSelect_ );
2169 compose_new_with_list( NULL, listAddress );
2170 mgu_free_dlist( listAddress );
2171 listAddress = NULL;
2175 static void addressbook_list_row_selected( GtkCTree *clist,
2176 GtkCTreeNode *node,
2177 gint column,
2178 gpointer data )
2180 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2181 AddrItemObject *aio = NULL;
2182 AddressObject *pobj = NULL;
2183 AdapterDSource *ads = NULL;
2184 AddressDataSource *ds = NULL;
2186 gtk_entry_set_text( entry, "" );
2187 addrbook.listSelected = node;
2189 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2190 if( pobj == NULL ) return;
2192 if( pobj->type == ADDR_DATASOURCE ) {
2193 ads = ADAPTER_DSOURCE(pobj);
2194 ds = ads->dataSource;
2196 else if( pobj->type != ADDR_INTERFACE ) {
2197 ds = addressbook_find_datasource( addrbook.treeSelected );
2200 aio = gtk_ctree_node_get_row_data( clist, node );
2201 if( aio ) {
2202 /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
2203 addressbook_list_select_add( aio, ds );
2206 addressbook_list_menu_setup();
2208 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2209 addressbook_edit_address_cb(NULL, 0, NULL);
2212 static void addressbook_list_row_unselected( GtkCTree *ctree,
2213 GtkCTreeNode *node,
2214 gint column,
2215 gpointer data )
2217 AddrItemObject *aio;
2219 aio = gtk_ctree_node_get_row_data( ctree, node );
2220 if( aio != NULL ) {
2221 /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2222 addressbook_list_select_remove( aio );
2225 if (!prefs_common.addressbook_use_editaddress_dialog)
2226 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2229 /* from gdkevents.c */
2230 #define DOUBLE_CLICK_TIME 250
2232 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2233 GdkEventButton *event,
2234 gpointer data)
2236 static guint32 lasttime = 0;
2237 if( ! event ) return FALSE;
2239 addressbook_list_menu_setup();
2241 if( event->button == 3 ) {
2242 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2243 event->button, event->time );
2244 } else if (event->button == 1) {
2245 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2246 if (prefs_common.add_address_by_click &&
2247 addrbook.target_compose)
2248 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2249 else
2250 if (prefs_common.addressbook_use_editaddress_dialog)
2251 addressbook_edit_address_cb(NULL, 0, NULL);
2253 lasttime = 0;
2254 } else
2255 lasttime = event->time;
2258 return FALSE;
2261 static gboolean addressbook_list_button_released(GtkWidget *widget,
2262 GdkEventButton *event,
2263 gpointer data)
2265 return FALSE;
2268 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2269 GdkEventButton *event,
2270 gpointer data)
2272 GtkCList *clist = GTK_CLIST(ctree);
2273 gint row, column;
2274 AddressObject *obj = NULL;
2275 AdapterDSource *ads = NULL;
2276 AddressInterface *iface = NULL;
2277 AddressDataSource *ds = NULL;
2278 gboolean canEdit = FALSE;
2279 gboolean canDelete = FALSE;
2280 gboolean canCut = FALSE;
2281 gboolean canCopy = FALSE;
2282 gboolean canPaste = FALSE;
2283 gboolean canTreeCut = FALSE;
2284 gboolean canTreeCopy = FALSE;
2285 gboolean canTreePaste = FALSE;
2286 gboolean canLookup = FALSE;
2287 GtkCTreeNode *node = NULL;
2289 if( ! event ) return FALSE;
2290 addressbook_menubar_set_sensitive( FALSE );
2292 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2293 gtkut_clist_set_focus_row(clist, row);
2294 obj = gtk_clist_get_row_data( clist, row );
2297 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2299 if( obj == NULL ) return FALSE;
2300 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2302 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2303 canTreePaste = TRUE;
2306 if (obj->type == ADDR_INTERFACE) {
2307 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2308 iface = adapter->interface;
2309 canEdit = FALSE;
2310 canDelete = FALSE;
2311 canTreeCopy = FALSE;
2312 if( iface->readOnly ) {
2313 canTreePaste = FALSE;
2315 else {
2316 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2317 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2319 if( iface->externalQuery ) canLookup = TRUE;
2321 if (obj->type == ADDR_DATASOURCE) {
2322 ads = ADAPTER_DSOURCE(obj);
2323 ds = ads->dataSource;
2324 if (!ds)
2325 goto just_set_sens;
2326 iface = ds->interface;
2327 if (!iface)
2328 goto just_set_sens;
2329 canEdit = TRUE;
2330 canDelete = TRUE;
2331 if( iface->readOnly ) {
2332 canTreePaste = FALSE;
2334 else {
2335 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2336 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2337 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2339 canTreeCopy = TRUE;
2340 if( iface->externalQuery ) canLookup = TRUE;
2342 else if (obj->type == ADDR_ITEM_FOLDER) {
2343 ds = addressbook_find_datasource( node );
2344 if (!ds) {
2345 goto just_set_sens;
2347 iface = ds->interface;
2348 if (!iface)
2349 goto just_set_sens;
2350 if( iface->readOnly ) {
2351 canTreePaste = FALSE;
2353 else {
2354 canEdit = TRUE;
2355 canDelete = TRUE;
2356 canTreeCut = TRUE;
2357 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2358 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2359 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2361 canTreeCopy = TRUE;
2363 if( iface->externalQuery ) {
2364 /* Enable deletion of LDAP folder */
2365 canLookup = TRUE;
2366 canDelete = TRUE;
2369 else if (obj->type == ADDR_ITEM_GROUP) {
2370 ds = addressbook_find_datasource( node );
2371 if (!ds)
2372 goto just_set_sens;
2373 iface = ds->interface;
2374 if (!iface)
2375 goto just_set_sens;
2376 if( ! iface->readOnly ) {
2377 canEdit = TRUE;
2378 canDelete = TRUE;
2379 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2380 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2383 else if (obj->type == ADDR_INTERFACE) {
2384 canTreePaste = FALSE;
2387 if( canEdit ) {
2388 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2390 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2391 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2393 just_set_sens:
2394 /* Enable edit */
2395 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2396 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2397 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2398 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2399 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2401 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2402 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2403 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2404 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2405 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2406 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2408 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2409 if( event->button == 3 ) {
2410 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2411 event->button, event->time);
2414 return FALSE;
2417 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2418 GdkEventButton *event,
2419 gpointer data)
2421 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2422 return FALSE;
2425 static void addressbook_new_folder_cb(gpointer data, guint action,
2426 GtkWidget *widget)
2428 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2429 AddressObject *obj = NULL;
2430 AddressDataSource *ds = NULL;
2431 AddressBookFile *abf = NULL;
2432 ItemFolder *parentFolder = NULL;
2433 ItemFolder *folder = NULL;
2435 if( ! addrbook.treeSelected ) return;
2436 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2437 if( obj == NULL ) return;
2438 ds = addressbook_find_datasource( addrbook.treeSelected );
2439 if( ds == NULL ) return;
2441 if( obj->type == ADDR_DATASOURCE ) {
2442 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2444 else if( obj->type == ADDR_ITEM_FOLDER ) {
2445 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2447 else {
2448 return;
2451 abf = ds->rawDataSource;
2452 if( abf == NULL ) return;
2453 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2454 if( folder ) {
2455 GtkCTreeNode *nn;
2456 nn = addressbook_node_add_folder(
2457 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2458 gtk_ctree_expand( ctree, addrbook.treeSelected );
2459 if( addrbook.treeSelected == addrbook.opened )
2460 addressbook_set_clist(obj, TRUE);
2465 static void addressbook_new_group_cb(gpointer data, guint action,
2466 GtkWidget *widget)
2468 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2469 AddressObject *obj = NULL;
2470 AddressDataSource *ds = NULL;
2471 AddressBookFile *abf = NULL;
2472 ItemFolder *parentFolder = NULL;
2473 ItemGroup *group = NULL;
2475 if( ! addrbook.treeSelected ) return;
2476 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2477 if( obj == NULL ) return;
2478 ds = addressbook_find_datasource( addrbook.treeSelected );
2479 if( ds == NULL ) return;
2481 if( obj->type == ADDR_DATASOURCE ) {
2482 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2484 else if( obj->type == ADDR_ITEM_FOLDER ) {
2485 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2487 else {
2488 return;
2491 abf = ds->rawDataSource;
2492 if( abf == NULL ) return;
2493 group = addressbook_edit_group( abf, parentFolder, NULL );
2494 if( group ) {
2495 GtkCTreeNode *nn;
2496 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2497 gtk_ctree_expand( ctree, addrbook.treeSelected );
2498 if( addrbook.treeSelected == addrbook.opened )
2499 addressbook_set_clist(obj, TRUE);
2504 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2506 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2507 gchar *text[1];
2508 guint8 spacing;
2509 GdkPixmap *pix_cl, *pix_op;
2510 GdkBitmap *mask_cl, *mask_op;
2511 gboolean is_leaf, expanded;
2513 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2514 &pix_cl, &mask_cl, &pix_op, &mask_op,
2515 &is_leaf, &expanded);
2516 gtk_sctree_set_node_info(ctree, node, name, spacing,
2517 pix_cl, mask_cl, pix_op, mask_op,
2518 is_leaf, expanded);
2522 * Edit data source.
2523 * \param obj Address object to edit.
2524 * \param node Node in tree.
2525 * \return New name of data source.
2527 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2528 gchar *newName = NULL;
2529 AddressDataSource *ds = NULL;
2530 AddressInterface *iface = NULL;
2531 AdapterDSource *ads = NULL;
2533 ds = addressbook_find_datasource( node );
2534 if( ds == NULL ) return NULL;
2535 iface = ds->interface;
2536 if( ! iface->haveLibrary ) return NULL;
2538 /* Read data from data source */
2539 if( addrindex_ds_get_modify_flag( ds ) ) {
2540 addrindex_ds_read_data( ds );
2543 if( ! addrindex_ds_get_read_flag( ds ) ) {
2544 addrindex_ds_read_data( ds );
2547 /* Handle edit */
2548 ads = ADAPTER_DSOURCE(obj);
2549 if( ads->subType == ADDR_BOOK ) {
2550 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2552 else if( ads->subType == ADDR_VCARD ) {
2553 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2555 #ifdef USE_JPILOT
2556 else if( ads->subType == ADDR_JPILOT ) {
2557 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2559 #endif
2560 #ifdef USE_LDAP
2561 else if( ads->subType == ADDR_LDAP ) {
2562 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2564 #endif
2565 else {
2566 return NULL;
2568 newName = obj->name;
2569 return newName;
2573 * Edit an object that is in the address tree area.
2575 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2576 GtkWidget *widget)
2578 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2579 AddressObject *obj;
2580 AddressDataSource *ds = NULL;
2581 AddressBookFile *abf = NULL;
2582 GtkCTreeNode *node = NULL, *parentNode = NULL;
2583 gchar *name = NULL;
2585 if( ! addrbook.treeSelected ) return;
2586 node = addrbook.treeSelected;
2587 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2588 obj = gtk_ctree_node_get_row_data( ctree, node );
2589 if( obj == NULL ) return;
2590 parentNode = GTK_CTREE_ROW(node)->parent;
2592 ds = addressbook_find_datasource( node );
2593 if( ds == NULL ) return;
2595 if( obj->type == ADDR_DATASOURCE ) {
2596 name = addressbook_edit_datasource( obj, node );
2597 if( name == NULL ) return;
2599 else {
2600 abf = ds->rawDataSource;
2601 if( abf == NULL ) return;
2602 if( obj->type == ADDR_ITEM_FOLDER ) {
2603 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2604 ItemFolder *item = adapter->itemFolder;
2605 ItemFolder *parentFolder = NULL;
2606 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2607 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2608 name = ADDRITEM_NAME(item);
2610 else if( obj->type == ADDR_ITEM_GROUP ) {
2611 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2612 ItemGroup *item = adapter->itemGroup;
2613 ItemFolder *parentFolder = NULL;
2614 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2615 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2616 name = ADDRITEM_NAME(item);
2619 if( name && parentNode ) {
2620 /* Update node in tree view */
2621 addressbook_change_node_name( node, name );
2622 gtk_sctree_sort_node(ctree, parentNode);
2623 gtk_ctree_expand( ctree, node );
2624 gtk_sctree_select( GTK_SCTREE( ctree), node );
2628 typedef enum {
2629 ADDRTREE_DEL_NONE,
2630 ADDRTREE_DEL_DATA,
2631 ADDRTREE_DEL_FOLDER_ONLY,
2632 ADDRTREE_DEL_FOLDER_ADDR
2633 } TreeItemDelType ;
2636 * Delete an item from the tree widget.
2637 * \param data Data passed in.
2638 * \param action Action.
2639 * \param widget Widget issuing callback.
2641 static void addressbook_treenode_delete_cb(
2642 gpointer data, guint action, GtkWidget *widget )
2644 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2645 GtkCTreeNode *node = NULL;
2646 AddressObject *obj;
2647 gchar *message;
2648 AlertValue aval;
2649 AddrBookBase *adbase;
2650 AddressCache *cache;
2651 AdapterDSource *ads = NULL;
2652 AddressInterface *iface = NULL;
2653 AddressDataSource *ds = NULL;
2654 gboolean remFlag = FALSE;
2655 TreeItemDelType delType;
2657 if( ! addrbook.treeSelected ) return;
2658 node = addrbook.treeSelected;
2659 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2661 obj = gtk_ctree_node_get_row_data( ctree, node );
2662 g_return_if_fail(obj != NULL);
2664 if( obj->type == ADDR_DATASOURCE ) {
2665 ads = ADAPTER_DSOURCE(obj);
2666 if( ads == NULL ) return;
2667 ds = ads->dataSource;
2668 if( ds == NULL ) return;
2670 else {
2671 /* Must be folder or something else */
2672 ds = addressbook_find_datasource( node );
2673 if( ds == NULL ) return;
2675 /* Only allow deletion from non-readOnly */
2676 iface = ds->interface;
2677 if( iface->readOnly ) {
2678 /* Allow deletion of query results */
2679 if( ! iface->externalQuery ) return;
2683 /* Confirm deletion */
2684 delType = ADDRTREE_DEL_NONE;
2685 if( obj->type == ADDR_ITEM_FOLDER ) {
2686 if( iface->externalQuery ) {
2687 message = g_strdup_printf( _(
2688 "Do you want to delete the query " \
2689 "results and addresses in '%s' ?" ),
2690 obj->name );
2691 aval = alertpanel( _("Delete"), message,
2692 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2693 g_free(message);
2694 if( aval == G_ALERTALTERNATE ) {
2695 delType = ADDRTREE_DEL_FOLDER_ADDR;
2698 else {
2699 message = g_strdup_printf
2700 ( _( "Do you want to delete '%s' ?"
2701 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2702 obj->name );
2703 aval = alertpanel( _("Delete folder"), message,
2704 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2705 g_free(message);
2706 if( aval == G_ALERTALTERNATE ) {
2707 delType = ADDRTREE_DEL_FOLDER_ONLY;
2709 else if( aval == G_ALERTOTHER ) {
2710 delType = ADDRTREE_DEL_FOLDER_ADDR;
2714 else if( obj->type == ADDR_ITEM_GROUP ) {
2715 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2716 "The addresses it contains will not be lost."), obj->name);
2717 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2718 "+" GTK_STOCK_DELETE, NULL);
2719 g_free(message);
2720 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2721 } else {
2722 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2723 "The addresses it contains will be lost."), obj->name);
2724 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2725 "+" GTK_STOCK_DELETE, NULL);
2726 g_free(message);
2727 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2729 if( delType == ADDRTREE_DEL_NONE ) return;
2731 /* Proceed with deletion */
2732 if( obj->type == ADDR_DATASOURCE ) {
2733 /* Remove node from tree */
2734 gtk_ctree_remove_node( ctree, node );
2736 /* Remove data source. */
2737 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2738 addrindex_free_datasource( ds );
2740 return;
2743 /* Get reference to cache */
2744 adbase = ( AddrBookBase * ) ds->rawDataSource;
2745 if( adbase == NULL ) return;
2746 cache = adbase->addressCache;
2748 /* Remove query results folder */
2749 if( iface->externalQuery ) {
2750 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2751 ItemFolder *folder = adapter->itemFolder;
2753 adapter->itemFolder = NULL;
2755 printf( "remove folder for ::%s::\n", obj->name );
2756 printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2757 printf( "-------------- remove results\n" );
2759 addrindex_remove_results( ds, folder );
2760 /* printf( "-------------- remove node\n" ); */
2761 gtk_ctree_remove_node( ctree, node );
2762 return;
2765 /* Code below is valid for regular address book deletion */
2766 if( obj->type == ADDR_ITEM_FOLDER ) {
2767 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2768 ItemFolder *item = adapter->itemFolder;
2770 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2771 /* Remove folder only */
2772 item = addrcache_remove_folder( cache, item );
2773 if( item ) {
2774 addritem_free_item_folder( item );
2775 addressbook_move_nodes_up( ctree, node );
2776 remFlag = TRUE;
2779 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2780 /* Remove folder and addresses */
2781 item = addrcache_remove_folder_delete( cache, item );
2782 if( item ) {
2783 addritem_free_item_folder( item );
2784 remFlag = TRUE;
2788 else if( obj->type == ADDR_ITEM_GROUP ) {
2789 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2790 ItemGroup *item = adapter->itemGroup;
2792 item = addrcache_remove_group( cache, item );
2793 if( item ) {
2794 addritem_free_item_group( item );
2795 remFlag = TRUE;
2799 if( remFlag ) {
2800 /* Remove node. */
2801 gtk_ctree_remove_node(ctree, node );
2805 void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2807 if( person && addrbook.treeSelected == addrbook.opened ) {
2808 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2809 addressbook_folder_refresh_one_person(
2810 GTK_CTREE(addrbook.clist), person );
2812 addressbook_address_list_set_focus();
2815 void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2817 if( person && addrbook.treeSelected == addrbook.opened) {
2818 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2819 addressbook_set_clist(
2820 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2821 addrbook.opened),
2822 TRUE);
2824 addressbook_address_list_set_focus();
2827 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2828 AddressObject *pobj = NULL;
2829 AddressDataSource *ds = NULL;
2830 AddressBookFile *abf = NULL;
2832 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2833 if( pobj == NULL ) return;
2834 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2835 if( ds == NULL ) return;
2837 abf = ds->rawDataSource;
2838 if( abf == NULL ) return;
2840 if( pobj->type == ADDR_DATASOURCE ) {
2841 if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) {
2842 /* New address */
2843 ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE,
2844 addrbook.editaddress_vbox,
2845 addressbook_new_address_from_book_post_cb,
2846 TRUE );
2847 if (prefs_common.addressbook_use_editaddress_dialog)
2848 addressbook_new_address_from_book_post_cb( person );
2851 else if( pobj->type == ADDR_ITEM_FOLDER ) {
2852 /* New address */
2853 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
2854 ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE,
2855 addrbook.editaddress_vbox,
2856 addressbook_new_address_from_folder_post_cb,
2857 TRUE );
2858 if (prefs_common.addressbook_use_editaddress_dialog)
2859 addressbook_new_address_from_folder_post_cb( person );
2861 else if( pobj->type == ADDR_ITEM_GROUP ) {
2862 /* New address in group */
2863 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
2864 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
2865 if (addrbook.treeSelected == addrbook.opened) {
2866 /* Change node name in tree. */
2867 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
2868 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2869 addressbook_set_clist(
2870 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2871 addrbook.opened),
2872 TRUE);
2878 * Search for specified child group node in address index tree.
2879 * \param parent Parent node.
2880 * \param group Group to find.
2882 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
2883 GtkCTreeNode *node = NULL;
2884 GtkCTreeRow *currRow;
2886 currRow = GTK_CTREE_ROW( parent );
2887 if( currRow ) {
2888 node = currRow->children;
2889 while( node ) {
2890 AddressObject *obj;
2892 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2893 if( obj->type == ADDR_ITEM_GROUP ) {
2894 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
2895 if( g == group ) return node;
2897 currRow = GTK_CTREE_ROW(node);
2898 node = currRow->sibling;
2901 return NULL;
2904 static AddressBookFile *addressbook_get_book_file() {
2905 AddressBookFile *abf = NULL;
2906 AddressDataSource *ds = NULL;
2908 ds = addressbook_find_datasource( addrbook.treeSelected );
2909 if( ds == NULL ) return NULL;
2910 if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
2911 return abf;
2914 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
2915 GtkCTreeNode *node;
2916 GtkCTreeRow *row;
2918 /* Remove existing folders and groups */
2919 row = GTK_CTREE_ROW( parent );
2920 if( row ) {
2921 while( (node = row->children) ) {
2922 gtk_ctree_remove_node( ctree, node );
2927 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
2928 GtkCTreeNode *parent, *child;
2929 GtkCTreeRow *currRow;
2930 currRow = GTK_CTREE_ROW( node );
2931 if( currRow ) {
2932 parent = currRow->parent;
2933 while( (child = currRow->children) ) {
2934 gtk_ctree_move( ctree, child, parent, node );
2936 gtk_sctree_sort_node( ctree, parent );
2940 void addressbook_edit_address_post_cb( ItemPerson *person )
2942 if( person ) {
2943 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
2944 invalidate_address_completion();
2946 addressbook_address_list_set_focus();
2949 void addressbook_address_list_set_focus( void )
2951 if (!prefs_common.addressbook_use_editaddress_dialog)
2952 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
2955 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2956 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2957 GtkCTree *ctree;
2958 AddressObject *obj = NULL, *pobj = NULL;
2959 AddressDataSource *ds = NULL;
2960 GtkCTreeNode *node = NULL, *parentNode = NULL;
2961 gchar *name = NULL;
2962 AddressBookFile *abf = NULL;
2964 if( addrbook.listSelected == NULL ) return;
2965 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2966 g_return_if_fail(obj != NULL);
2968 ctree = GTK_CTREE( addrbook.ctree );
2969 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2970 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
2972 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2973 if( ds == NULL ) return;
2975 abf = addressbook_get_book_file();
2977 if( obj->type == ADDR_ITEM_EMAIL ) {
2978 ItemEMail *email = ( ItemEMail * ) obj;
2979 if( email == NULL ) return;
2980 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
2981 /* Edit parent group */
2982 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
2983 ItemGroup *itemGrp = adapter->itemGroup;
2984 if( abf == NULL ) return;
2985 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
2986 name = ADDRITEM_NAME(itemGrp);
2987 node = addrbook.treeSelected;
2988 parentNode = GTK_CTREE_ROW(node)->parent;
2990 else {
2991 /* Edit person - email page */
2992 ItemPerson *person;
2993 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
2994 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
2995 addressbook_edit_address_post_cb,
2996 prefs_common.addressbook_use_editaddress_dialog?TRUE:FALSE )
2997 != NULL ) {
2998 if (prefs_common.addressbook_use_editaddress_dialog)
2999 addressbook_edit_address_post_cb( person );
3001 return;
3004 else if( obj->type == ADDR_ITEM_PERSON ) {
3005 /* Edit person - basic page */
3006 ItemPerson *person = ( ItemPerson * ) obj;
3007 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3008 addressbook_edit_address_post_cb,
3009 prefs_common.addressbook_use_editaddress_dialog?TRUE:FALSE )
3010 != NULL ) {
3011 if (prefs_common.addressbook_use_editaddress_dialog)
3012 addressbook_edit_address_post_cb( person );
3014 return;
3016 else if( obj->type == ADDR_ITEM_GROUP ) {
3017 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3018 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3019 parentNode = addrbook.treeSelected;
3020 node = addressbook_find_group_node( parentNode, itemGrp );
3021 name = ADDRITEM_NAME(itemGrp);
3022 invalidate_address_completion();
3024 else {
3025 return;
3028 /* Update tree node with node name */
3029 if( node == NULL ) return;
3030 addressbook_change_node_name( node, name );
3031 gtk_sctree_sort_node( ctree, parentNode );
3032 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3033 addressbook_set_clist(
3034 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3035 addrbook.opened),
3036 TRUE);
3039 static void addressbook_delete_address_cb(gpointer data, guint action,
3040 GtkWidget *widget)
3042 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3043 addressbook_del_clicked(NULL, NULL);
3044 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3047 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3049 addressbook_close();
3052 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3053 addressbook_export_to_file();
3056 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3057 if( node ) {
3058 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3059 if( person ) addritem_person_set_opened( person, TRUE );
3063 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3064 if( node ) {
3065 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3066 if( person ) addritem_person_set_opened( person, FALSE );
3070 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3071 gchar *str = NULL;
3072 gchar *eMailAlias = ADDRITEM_NAME(email);
3073 if( eMailAlias && *eMailAlias != '\0' ) {
3074 if( person ) {
3075 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3077 else {
3078 str = g_strdup( eMailAlias );
3081 return str;
3084 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3085 GList *items = itemGroup->listEMail;
3086 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3087 for( ; items != NULL; items = g_list_next( items ) ) {
3088 GtkCTreeNode *nodeEMail = NULL;
3089 gchar *text[N_LIST_COLS];
3090 ItemEMail *email = items->data;
3091 ItemPerson *person;
3092 gchar *str = NULL;
3094 if( ! email ) continue;
3096 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3097 str = addressbook_format_item_clist( person, email );
3098 if( str ) {
3099 text[COL_NAME] = str;
3101 else {
3102 text[COL_NAME] = ADDRITEM_NAME(person);
3104 text[COL_ADDRESS] = email->address;
3105 text[COL_REMARKS] = email->remarks;
3106 nodeEMail = gtk_sctree_insert_node(
3107 clist, NULL, NULL,
3108 text, FOLDER_SPACING,
3109 atci->iconXpm, atci->maskXpm,
3110 atci->iconXpmOpen, atci->maskXpmOpen,
3111 FALSE, FALSE );
3112 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3113 g_free( str );
3114 str = NULL;
3118 static void addressbook_folder_load_one_person(
3119 GtkCTree *clist, ItemPerson *person,
3120 AddressTypeControlItem *atci,
3121 AddressTypeControlItem *atciMail )
3123 GtkCTreeNode *nodePerson = NULL;
3124 GtkCTreeNode *nodeEMail = NULL;
3125 gchar *text[N_LIST_COLS];
3126 gboolean flgFirst = TRUE, haveAddr = FALSE;
3127 GList *node;
3129 if( person == NULL ) return;
3131 text[COL_NAME] = "";
3132 node = person->listEMail;
3133 while( node ) {
3134 ItemEMail *email = node->data;
3135 gchar *eMailAddr = NULL;
3136 node = g_list_next( node );
3138 text[COL_ADDRESS] = email->address;
3139 text[COL_REMARKS] = email->remarks;
3140 eMailAddr = ADDRITEM_NAME(email);
3141 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3142 if( flgFirst ) {
3143 /* First email belongs with person */
3144 gchar *str = addressbook_format_item_clist( person, email );
3145 if( str ) {
3146 text[COL_NAME] = str;
3148 else {
3149 text[COL_NAME] = ADDRITEM_NAME(person);
3151 nodePerson = gtk_sctree_insert_node(
3152 clist, NULL, NULL,
3153 text, FOLDER_SPACING,
3154 atci->iconXpm, atci->maskXpm,
3155 atci->iconXpmOpen, atci->maskXpmOpen,
3156 FALSE, person->isOpened );
3157 g_free( str );
3158 str = NULL;
3159 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3161 else {
3162 /* Subsequent email is a child node of person */
3163 text[COL_NAME] = ADDRITEM_NAME(email);
3164 nodeEMail = gtk_sctree_insert_node(
3165 clist, nodePerson, NULL,
3166 text, FOLDER_SPACING,
3167 atciMail->iconXpm, atciMail->maskXpm,
3168 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3169 FALSE, TRUE );
3170 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3172 flgFirst = FALSE;
3173 haveAddr = TRUE;
3175 if( ! haveAddr ) {
3176 /* Have name without EMail */
3177 text[COL_NAME] = ADDRITEM_NAME(person);
3178 text[COL_ADDRESS] = "";
3179 text[COL_REMARKS] = "";
3180 nodePerson = gtk_sctree_insert_node(
3181 clist, NULL, NULL,
3182 text, FOLDER_SPACING,
3183 atci->iconXpm, atci->maskXpm,
3184 atci->iconXpmOpen, atci->maskXpmOpen,
3185 FALSE, person->isOpened );
3186 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3188 return;
3191 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3192 GList *items;
3193 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3194 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3196 if( atci == NULL ) return;
3197 if( atciMail == NULL ) return;
3199 /* Load email addresses */
3200 items = addritem_folder_get_person_list( itemFolder );
3201 for( ; items != NULL; items = g_list_next( items ) ) {
3202 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3204 /* Free up the list */
3205 mgu_clear_list( items );
3206 g_list_free( items );
3209 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3210 addrbook.listSelected = NULL;
3211 gtk_ctree_remove_node( clist, node );
3212 addressbook_menubar_set_sensitive( FALSE );
3213 addressbook_menuitem_set_sensitive(
3214 gtk_ctree_node_get_row_data(
3215 GTK_CTREE(clist), addrbook.treeSelected ),
3216 addrbook.treeSelected );
3219 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3220 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3221 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3222 GtkCTreeNode *node;
3223 if( atci == NULL ) return;
3224 if( atciMail == NULL ) return;
3225 if( person == NULL ) return;
3226 /* unload the person */
3228 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3229 if( node )
3230 addressbook_folder_remove_node( clist, node );
3231 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3232 gtk_sctree_sort_node( clist, NULL );
3233 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3234 if( node ) {
3235 gtk_sctree_select( GTK_SCTREE(clist), node );
3236 if (!gtk_ctree_node_is_visible( clist, node ) )
3237 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3241 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3242 GtkCTreeNode *node;
3243 gint row;
3245 if( person == NULL ) return;
3246 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3247 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3248 if( node ) {
3249 addressbook_folder_remove_node( clist, node );
3253 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3254 GList *items;
3255 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3257 /* Load any groups */
3258 if( ! atci ) return;
3259 items = addritem_folder_get_group_list( itemFolder );
3260 for( ; items != NULL; items = g_list_next( items ) ) {
3261 GtkCTreeNode *nodeGroup = NULL;
3262 gchar *text[N_LIST_COLS];
3263 ItemGroup *group = items->data;
3264 if( group == NULL ) continue;
3265 text[COL_NAME] = ADDRITEM_NAME(group);
3266 text[COL_ADDRESS] = "";
3267 text[COL_REMARKS] = "";
3268 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3269 text, FOLDER_SPACING,
3270 atci->iconXpm, atci->maskXpm,
3271 atci->iconXpmOpen, atci->maskXpmOpen,
3272 FALSE, FALSE);
3273 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3274 gtk_sctree_sort_node(clist, NULL);
3276 /* Free up the list */
3277 mgu_clear_list( items );
3278 g_list_free( items );
3282 * Search ctree widget callback function.
3283 * \param pA Pointer to node.
3284 * \param pB Pointer to data item being sought.
3285 * \return Zero (0) if group found.
3287 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3288 AddressObject *aoA;
3290 aoA = ( AddressObject * ) pA;
3291 if( aoA->type == ADDR_ITEM_GROUP ) {
3292 ItemGroup *group, *grp;
3294 grp = ADAPTER_GROUP(aoA)->itemGroup;
3295 group = ( ItemGroup * ) pB;
3296 if( grp == group ) return 0; /* Found group */
3298 return 1;
3302 * Search ctree widget callback function.
3303 * \param pA Pointer to node.
3304 * \param pB Pointer to data item being sought.
3305 * \return Zero (0) if folder found.
3307 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3308 AddressObject *aoA;
3310 aoA = ( AddressObject * ) pA;
3311 if( aoA->type == ADDR_ITEM_FOLDER ) {
3312 ItemFolder *folder, *fld;
3314 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3315 folder = ( ItemFolder * ) pB;
3316 if( fld == folder ) return 0; /* Found folder */
3318 return 1;
3322 * Remove folder and group nodes from tree widget for items contained ("cut")
3323 * in clipboard.
3325 static void addressbook_treenode_remove_item( void ) {
3326 GList *node;
3327 AddrSelectItem *cutItem;
3328 AddressCache *cache;
3329 AddrItemObject *aio;
3330 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3331 GtkCTreeNode *tn;
3333 node = _clipBoard_->objectList;
3334 while( node ) {
3335 cutItem = node->data;
3336 node = g_list_next( node );
3337 cache = addrindex_get_cache(
3338 _clipBoard_->addressIndex, cutItem->cacheID );
3339 if( cache == NULL ) continue;
3340 aio = addrcache_get_object( cache, cutItem->uid );
3341 if( aio ) {
3342 tn = NULL;
3343 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3344 ItemFolder *folder;
3346 folder = ( ItemFolder * ) aio;
3347 tn = gtk_ctree_find_by_row_data_custom(
3348 ctree, NULL, folder,
3349 addressbook_treenode_find_folder_cb );
3351 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3352 ItemGroup *group;
3354 group = ( ItemGroup * ) aio;
3355 tn = gtk_ctree_find_by_row_data_custom(
3356 ctree, NULL, group,
3357 addressbook_treenode_find_group_cb );
3360 if( tn ) {
3361 /* Free up adapter and remove node. */
3362 gtk_ctree_remove_node( ctree, tn );
3369 * Find parent datasource for specified tree node.
3370 * \param node Node to test.
3371 * \return Data source, or NULL if not found.
3373 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3374 AddressDataSource *ds = NULL;
3375 AddressObject *ao;
3377 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3379 while( node ) {
3380 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3381 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3382 if( ao ) {
3383 /* printf( "ao->type = %d\n", ao->type ); */
3384 if( ao->type == ADDR_DATASOURCE ) {
3385 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3386 /* printf( "found it\n" ); */
3387 ds = ads->dataSource;
3388 break;
3391 node = GTK_CTREE_ROW(node)->parent;
3393 return ds;
3397 * Load address list widget with children of specified object.
3398 * \param obj Parent object to be loaded.
3400 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3401 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3402 GtkCList *clist = GTK_CLIST(addrbook.clist);
3403 AddressDataSource *ds = NULL;
3404 AdapterDSource *ads = NULL;
3405 static AddressObject *last_obj = NULL;
3407 if (addrbook.clist == NULL) {
3408 return;
3410 if (obj == last_obj && !refresh)
3411 return;
3413 last_obj = obj;
3414 if( obj == NULL ) {
3415 gtk_clist_clear(clist);
3416 return;
3419 if( obj->type == ADDR_INTERFACE ) {
3420 /* printf( "set_clist: loading datasource...\n" ); */
3421 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3422 return;
3425 gtk_clist_freeze(clist);
3426 gtk_clist_clear(clist);
3428 if( obj->type == ADDR_DATASOURCE ) {
3429 ads = ADAPTER_DSOURCE(obj);
3430 ds = ADAPTER_DSOURCE(obj)->dataSource;
3431 if( ds ) {
3432 /* Load root folder */
3433 ItemFolder *rootFolder = NULL;
3434 rootFolder = addrindex_ds_get_root_folder( ds );
3435 addressbook_folder_load_person(
3436 ctreelist, addrindex_ds_get_root_folder( ds ) );
3437 addressbook_folder_load_group(
3438 ctreelist, addrindex_ds_get_root_folder( ds ) );
3441 else {
3442 if( obj->type == ADDR_ITEM_GROUP ) {
3443 /* Load groups */
3444 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3445 addressbook_load_group( ctreelist, itemGroup );
3447 else if( obj->type == ADDR_ITEM_FOLDER ) {
3448 /* Load folders */
3449 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3450 addressbook_folder_load_person( ctreelist, itemFolder );
3451 addressbook_folder_load_group( ctreelist, itemFolder );
3454 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3455 clist->focus_row = -1;
3456 gtk_clist_thaw(clist);
3460 * Call back function to free adaptor. Call back is setup by function
3461 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3462 * called when the address book tree widget node is removed by calling
3463 * function gtk_ctree_remove_node().
3465 * \param data Tree node's row data.
3467 static void addressbook_free_treenode( gpointer data ) {
3468 AddressObject *ao;
3470 ao = ( AddressObject * ) data;
3471 if( ao == NULL ) return;
3472 if( ao->type == ADDR_INTERFACE ) {
3473 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3474 addrbookctl_free_interface( ai );
3476 else if( ao->type == ADDR_DATASOURCE ) {
3477 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3478 addrbookctl_free_datasource( ads );
3480 else if( ao->type == ADDR_ITEM_FOLDER ) {
3481 AdapterFolder *af = ADAPTER_FOLDER(ao);
3482 addrbookctl_free_folder( af );
3484 else if( ao->type == ADDR_ITEM_GROUP ) {
3485 AdapterGroup *ag = ADAPTER_GROUP(ao);
3486 addrbookctl_free_group( ag );
3491 * Create new adaptor for specified data source.
3493 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3494 AddressObjectType otype, gchar *name )
3496 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3497 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3498 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3499 adapter->dataSource = ds;
3500 adapter->subType = otype;
3501 return adapter;
3504 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3505 ADDRESS_OBJECT_NAME(adapter) =
3506 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3510 * Load tree from address index with the initial data.
3512 static void addressbook_load_tree( void ) {
3513 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3514 GList *nodeIf, *nodeDS;
3515 AdapterInterface *adapter;
3516 AddressInterface *iface;
3517 AddressTypeControlItem *atci;
3518 AddressDataSource *ds;
3519 AdapterDSource *ads;
3520 GtkCTreeNode *node, *newNode;
3521 gchar *name;
3523 nodeIf = _addressInterfaceList_;
3524 while( nodeIf ) {
3525 adapter = nodeIf->data;
3526 node = adapter->treeNode;
3527 iface = adapter->interface;
3528 atci = adapter->atci;
3529 if( iface ) {
3530 if( iface->useInterface ) {
3531 /* Load data sources below interface node */
3532 nodeDS = iface->listSource;
3533 while( nodeDS ) {
3534 ds = nodeDS->data;
3535 newNode = NULL;
3536 name = addrindex_ds_get_name( ds );
3537 ads = addressbook_create_ds_adapter(
3538 ds, atci->objectType, name );
3539 newNode = addressbook_add_object(
3540 node, ADDRESS_OBJECT(ads) );
3541 nodeDS = g_list_next( nodeDS );
3543 gtk_ctree_expand( ctree, node );
3546 nodeIf = g_list_next( nodeIf );
3551 * Convert the old address book to new format.
3553 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3554 gboolean retVal = FALSE;
3555 gboolean errFlag = TRUE;
3556 gchar *msg = NULL;
3558 /* Read old address book, performing conversion */
3559 debug_print( "Reading and converting old address book...\n" );
3560 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3561 addrindex_read_data( addrIndex );
3562 if( addrIndex->retVal == MGU_NO_FILE ) {
3563 /* We do not have a file - new user */
3564 debug_print( "New user... create new books...\n" );
3565 addrindex_create_new_books( addrIndex );
3566 if( addrIndex->retVal == MGU_SUCCESS ) {
3567 /* Save index file */
3568 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3569 addrindex_save_data( addrIndex );
3570 if( addrIndex->retVal == MGU_SUCCESS ) {
3571 retVal = TRUE;
3572 errFlag = FALSE;
3574 else {
3575 msg = _( "New user, could not save index file." );
3578 else {
3579 msg = _( "New user, could not save address book files." );
3582 else {
3583 /* We have an old file */
3584 if( addrIndex->wasConverted ) {
3585 /* Converted successfully - save address index */
3586 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3587 addrindex_save_data( addrIndex );
3588 if( addrIndex->retVal == MGU_SUCCESS ) {
3589 msg = _( "Old address book converted successfully." );
3590 retVal = TRUE;
3591 errFlag = FALSE;
3593 else {
3594 msg = _("Old address book converted,\n"
3595 "could not save new address index file." );
3598 else {
3599 /* File conversion failed - just create new books */
3600 debug_print( "File conversion failed... just create new books...\n" );
3601 addrindex_create_new_books( addrIndex );
3602 if( addrIndex->retVal == MGU_SUCCESS ) {
3603 /* Save index */
3604 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3605 addrindex_save_data( addrIndex );
3606 if( addrIndex->retVal == MGU_SUCCESS ) {
3607 msg = _("Could not convert address book,\n"
3608 "but created empty new address book files." );
3609 retVal = TRUE;
3610 errFlag = FALSE;
3612 else {
3613 msg = _("Could not convert address book,\n"
3614 "could not save new address index file." );
3617 else {
3618 msg = _("Could not convert address book\n"
3619 "and could not create new address book files." );
3623 if( errFlag ) {
3624 debug_print( "Error\n%s\n", msg );
3625 alertpanel_full(_("Addressbook conversion error"), msg,
3626 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3627 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3629 else if( msg ) {
3630 debug_print( "Warning\n%s\n", msg );
3631 alertpanel_full(_("Addressbook conversion error"), msg,
3632 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3633 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3636 return retVal;
3639 void addressbook_read_file( void ) {
3640 AddressIndex *addrIndex = NULL;
3642 debug_print( "Reading address index...\n" );
3643 if( _addressIndex_ ) {
3644 debug_print( "address book already read!!!\n" );
3645 return;
3648 addrIndex = addrindex_create_index();
3649 addrindex_initialize();
3651 /* Use new address book index. */
3652 addrindex_set_file_path( addrIndex, get_rc_dir() );
3653 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3654 addrindex_read_data( addrIndex );
3655 if( addrIndex->retVal == MGU_NO_FILE ) {
3656 /* Conversion required */
3657 debug_print( "Converting...\n" );
3658 if( addressbook_convert( addrIndex ) ) {
3659 _addressIndex_ = addrIndex;
3662 else if( addrIndex->retVal == MGU_SUCCESS ) {
3663 _addressIndex_ = addrIndex;
3665 else {
3666 /* Error reading address book */
3667 debug_print( "Could not read address index.\n" );
3668 addrindex_print_index( addrIndex, stdout );
3669 alertpanel_full(_("Addressbook Error"),
3670 _("Could not read address index"),
3671 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3672 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3674 debug_print( "done.\n" );
3678 * Add object into the address index tree widget.
3679 * Enter: node Parent node.
3680 * obj Object to add.
3681 * Return: Node that was added, or NULL if object not added.
3683 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3684 AddressObject *obj)
3686 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3687 GtkCTreeNode *added;
3688 AddressObject *pobj;
3689 AddressObjectType otype;
3690 AddressTypeControlItem *atci = NULL;
3692 g_return_val_if_fail(node != NULL, NULL);
3693 g_return_val_if_fail(obj != NULL, NULL);
3695 pobj = gtk_ctree_node_get_row_data(ctree, node);
3696 g_return_val_if_fail(pobj != NULL, NULL);
3698 /* Determine object type to be displayed */
3699 if( obj->type == ADDR_DATASOURCE ) {
3700 otype = ADAPTER_DSOURCE(obj)->subType;
3702 else {
3703 otype = obj->type;
3706 /* Handle any special conditions. */
3707 added = node;
3708 atci = addrbookctl_lookup( otype );
3709 if( atci ) {
3710 if( atci->showInTree ) {
3711 /* Add object to tree */
3712 gchar **name;
3713 name = &obj->name;
3714 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3715 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3716 atci->treeLeaf, atci->treeExpand );
3717 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3718 addressbook_free_treenode );
3722 gtk_sctree_sort_node(ctree, node);
3724 return added;
3728 * Add group into the address index tree.
3729 * \param node Parent node.
3730 * \param ds Data source.
3731 * \param itemGroup Group to add.
3732 * \return Inserted node.
3734 static GtkCTreeNode *addressbook_node_add_group(
3735 GtkCTreeNode *node, AddressDataSource *ds,
3736 ItemGroup *itemGroup )
3738 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3739 GtkCTreeNode *newNode;
3740 AdapterGroup *adapter;
3741 AddressTypeControlItem *atci = NULL;
3742 gchar **name;
3744 if( ds == NULL ) return NULL;
3745 if( node == NULL || itemGroup == NULL ) return NULL;
3747 name = &itemGroup->obj.name;
3749 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3751 adapter = g_new0( AdapterGroup, 1 );
3752 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
3753 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
3754 adapter->itemGroup = itemGroup;
3756 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3757 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3758 atci->treeLeaf, atci->treeExpand );
3759 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3760 addressbook_free_treenode );
3761 gtk_sctree_sort_node( ctree, node );
3762 return newNode;
3766 * Add folder into the address index tree. Only visible folders are loaded into
3767 * the address index tree. Note that the root folder is not inserted into the
3768 * tree.
3770 * \param node Parent node.
3771 * \param ds Data source.
3772 * \param itemFolder Folder to add.
3773 * \param otype Object type to display.
3774 * \return Inserted node for the folder.
3776 static GtkCTreeNode *addressbook_node_add_folder(
3777 GtkCTreeNode *node, AddressDataSource *ds,
3778 ItemFolder *itemFolder, AddressObjectType otype )
3780 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3781 GtkCTreeNode *newNode = NULL;
3782 AdapterFolder *adapter;
3783 AddressTypeControlItem *atci = NULL;
3784 GList *listItems = NULL;
3785 gchar *name;
3786 ItemFolder *rootFolder;
3788 /* Only visible folders */
3789 if( itemFolder->isHidden ) return NULL;
3791 if( ds == NULL ) return NULL;
3792 if( node == NULL || itemFolder == NULL ) return NULL;
3794 /* Determine object type */
3795 atci = addrbookctl_lookup( otype );
3796 if( atci == NULL ) return NULL;
3798 rootFolder = addrindex_ds_get_root_folder( ds );
3799 if( itemFolder == rootFolder ) {
3800 newNode = node;
3802 else {
3803 adapter = g_new0( AdapterFolder, 1 );
3804 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
3805 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
3806 adapter->itemFolder = itemFolder;
3808 name = ADDRITEM_NAME(itemFolder);
3809 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
3810 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3811 atci->treeLeaf, atci->treeExpand );
3812 if( newNode ) {
3813 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3814 addressbook_free_treenode );
3818 listItems = itemFolder->listFolder;
3819 while( listItems ) {
3820 ItemFolder *item = listItems->data;
3821 addressbook_node_add_folder( newNode, ds, item, otype );
3822 listItems = g_list_next( listItems );
3824 listItems = itemFolder->listGroup;
3825 while( listItems ) {
3826 ItemGroup *item = listItems->data;
3827 addressbook_node_add_group( newNode, ds, item );
3828 listItems = g_list_next( listItems );
3830 gtk_sctree_sort_node( ctree, node );
3831 return newNode;
3834 void addressbook_export_to_file( void ) {
3835 if( _addressIndex_ ) {
3836 /* Save all new address book data */
3837 debug_print( "Saving address books...\n" );
3838 addrindex_save_all_books( _addressIndex_ );
3840 debug_print( "Exporting addressbook to file...\n" );
3841 addrindex_save_data( _addressIndex_ );
3842 if( _addressIndex_->retVal != MGU_SUCCESS ) {
3843 addrindex_print_index( _addressIndex_, stdout );
3846 /* Notify address completion of new data */
3847 invalidate_address_completion();
3851 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
3853 if (event && event->keyval == GDK_Return)
3854 addressbook_lup_clicked(NULL, NULL);
3855 return FALSE;
3859 * Comparison using cell contents (text in first column). Used for sort
3860 * address index widget.
3862 static gint addressbook_treenode_compare_func(
3863 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
3865 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
3866 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
3867 gchar *name1 = NULL, *name2 = NULL;
3868 if( cell1 ) name1 = cell1->u.text;
3869 if( cell2 ) name2 = cell2->u.text;
3870 if( ! name1 ) return ( name2 != NULL );
3871 if( ! name2 ) return -1;
3872 return g_utf8_collate( name1, name2 );
3875 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
3876 AdapterDSource *ads;
3877 AdapterInterface *adapter;
3878 GtkCTreeNode *newNode;
3880 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
3881 if( adapter == NULL ) return;
3882 ads = addressbook_edit_book( _addressIndex_, NULL );
3883 if( ads ) {
3884 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3885 if( newNode ) {
3886 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3887 addrbook.treeSelected = newNode;
3892 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
3893 AdapterDSource *ads;
3894 AdapterInterface *adapter;
3895 GtkCTreeNode *newNode;
3897 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
3898 if( adapter == NULL ) return;
3899 ads = addressbook_edit_vcard( _addressIndex_, NULL );
3900 if( ads ) {
3901 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3902 if( newNode ) {
3903 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3904 addrbook.treeSelected = newNode;
3909 #ifdef USE_JPILOT
3910 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
3911 AdapterDSource *ads;
3912 AdapterInterface *adapter;
3913 AddressInterface *iface;
3914 GtkCTreeNode *newNode;
3916 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
3917 if( adapter == NULL ) return;
3918 iface = adapter->interface;
3919 if( ! iface->haveLibrary ) return;
3920 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
3921 if( ads ) {
3922 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3923 if( newNode ) {
3924 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3925 addrbook.treeSelected = newNode;
3929 #endif
3931 #ifdef USE_LDAP
3932 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
3933 AdapterDSource *ads;
3934 AdapterInterface *adapter;
3935 AddressInterface *iface;
3936 GtkCTreeNode *newNode;
3938 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
3939 if( adapter == NULL ) return;
3940 iface = adapter->interface;
3941 if( ! iface->haveLibrary ) return;
3942 ads = addressbook_edit_ldap( _addressIndex_, NULL );
3943 if( ads ) {
3944 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3945 if( newNode ) {
3946 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3947 addrbook.treeSelected = newNode;
3951 #endif
3954 * Display address search status message.
3955 * \param queryType Query type.
3956 * \param status Status/Error code.
3958 static void addressbook_search_message( gint queryType, gint sts ) {
3959 gchar *desc = NULL;
3960 *addressbook_msgbuf = '\0';
3962 if( sts != MGU_SUCCESS ) {
3963 if( queryType == ADDRQUERY_LDAP ) {
3964 #ifdef USE_LDAP
3965 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
3966 #endif
3969 if( desc ) {
3970 g_snprintf( addressbook_msgbuf,
3971 sizeof(addressbook_msgbuf), "%s", desc );
3972 addressbook_status_show( addressbook_msgbuf );
3974 else {
3975 addressbook_status_show( "" );
3980 * Refresh addressbook by forcing refresh of current selected object in
3981 * tree.
3983 static void addressbook_refresh_current( void ) {
3984 AddressObject *obj;
3985 GtkCTree *ctree;
3987 ctree = GTK_CTREE(addrbook.ctree);
3988 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3989 if( obj == NULL ) return;
3990 addressbook_set_clist( obj, TRUE );
3994 * Message that is displayed whilst a query is executing in a background
3995 * thread.
3997 static gchar *_tempMessage_ = N_( "Busy searching..." );
4000 * Address search idle function. This function is called during UI idle time
4001 * while a search is in progress.
4003 * \param data Idler data.
4005 static void addressbook_search_idle( gpointer data ) {
4007 gint queryID;
4009 queryID = GPOINTER_TO_INT( data );
4010 printf( "addressbook_ldap_idle... queryID=%d\n", queryID );
4015 * Search completion callback function. This removes the query from the idle
4016 * list.
4018 * \param queryID Query ID of search request.
4020 void addressbook_clear_idler( gint queryID ) {
4021 gpointer ptrQID;
4023 /* Remove idler function */
4024 /* printf( "addressbook_clear_idler::%d::\n", queryID ); */
4025 ptrQID = GINT_TO_POINTER( queryID );
4026 if( ptrQID ) {
4027 g_idle_remove_by_data( ptrQID );
4032 * Search completion callback function. This removes the query from the idle
4033 * list.
4035 * \param sender Sender of query.
4036 * \param queryID Query ID of search request.
4037 * \param status Search status.
4038 * \param data Query data.
4040 static void addressbook_search_callback_end(
4041 gpointer sender, gint queryID, gint status, gpointer data )
4043 gpointer ptrQID;
4044 QueryRequest *req;
4045 AddrQueryObject *aqo;
4047 /* Remove idler function */
4048 ptrQID = GINT_TO_POINTER( queryID );
4049 if( ptrQID ) {
4050 g_idle_remove_by_data( ptrQID );
4053 /* Refresh addressbook contents */
4054 addressbook_refresh_current();
4055 req = qrymgr_find_request( queryID );
4056 if( req != NULL ) {
4057 aqo = ( AddrQueryObject * ) req->queryList->data;
4058 addressbook_search_message( aqo->queryType, status );
4061 /* Stop the search */
4062 addrindex_stop_search( queryID );
4066 * Label (a format string) that is used to name each folder.
4068 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
4071 * Perform search.
4073 * \param ds Data source to search.
4074 * \param searchTerm String to lookup.
4075 * \param pNode Parent data source node.
4077 static void addressbook_perform_search(
4078 AddressDataSource *ds, gchar *searchTerm,
4079 GtkCTreeNode *pNode )
4081 AddrBookBase *adbase;
4082 AddressCache *cache;
4083 ItemFolder *folder;
4084 GtkCTree *ctree;
4085 GtkCTreeNode *nNode;
4086 gchar *name;
4087 gint queryID;
4088 guint idleID;
4089 AddressObjectType aoType = ADDR_NONE;
4091 /* Setup a query */
4092 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4094 if( ds->type == ADDR_IF_LDAP ) {
4095 #if USE_LDAP
4096 aoType = ADDR_LDAP_QUERY;
4097 #endif
4099 else {
4100 return;
4103 /* Get reference to address cache */
4104 adbase = ( AddrBookBase * ) ds->rawDataSource;
4105 cache = adbase->addressCache;
4107 /* Create a folder for the search results */
4108 folder = addrcache_add_new_folder( cache, NULL );
4109 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4110 addritem_folder_set_name( folder, name );
4111 addritem_folder_set_remarks( folder, "" );
4112 g_free( name );
4114 /* Now let's see the folder */
4115 ctree = GTK_CTREE(addrbook.ctree);
4116 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
4117 gtk_ctree_expand( ctree, pNode );
4118 if( nNode ) {
4119 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
4120 addrbook.treeSelected = nNode;
4123 /* Setup the search */
4124 queryID = addrindex_setup_explicit_search(
4125 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4126 if( queryID == 0 ) return;
4128 /* Set up idler function */
4129 idleID = g_idle_add(
4130 ( GtkFunction ) addressbook_search_idle,
4131 GINT_TO_POINTER( queryID ) );
4133 /* Start search, sit back and wait for something to happen */
4134 addrindex_start_search( queryID );
4136 addressbook_status_show( _tempMessage_ );
4140 * Lookup button handler. Address search is only performed against
4141 * address interfaces for external queries.
4143 * \param button Lookup button widget.
4144 * \param data Data object.
4146 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4147 GtkCTree *ctree;
4148 AddressObject *obj;
4149 AddressDataSource *ds;
4150 AddressInterface *iface;
4151 gchar *searchTerm;
4152 GtkCTreeNode *node, *parentNode;
4154 node = addrbook.treeSelected;
4155 if( ! node ) return;
4156 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4158 ctree = GTK_CTREE(addrbook.ctree);
4159 obj = gtk_ctree_node_get_row_data( ctree, node );
4160 if( obj == NULL ) return;
4162 ds = addressbook_find_datasource( node );
4163 if( ds == NULL ) return;
4165 /* We must have a datasource that is an external interface */
4166 iface = ds->interface;
4167 if( ! iface->haveLibrary ) return;
4168 if( ! iface->externalQuery ) return;
4170 searchTerm =
4171 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4172 g_strchomp( searchTerm );
4174 if( obj->type == ADDR_ITEM_FOLDER ) {
4175 parentNode = GTK_CTREE_ROW(node)->parent;
4177 else {
4178 parentNode = node;
4180 addressbook_perform_search( ds, searchTerm, parentNode );
4182 gtk_widget_grab_focus( addrbook.entry );
4184 g_free( searchTerm );
4187 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4188 addressbook_close();
4191 #ifdef USE_LDAP
4193 * Browse address entry for highlighted entry.
4195 static void addressbook_browse_entry_cb(void)
4197 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4198 AddressObject *obj;
4199 AddressDataSource *ds;
4200 AddressInterface *iface;
4201 ItemPerson *person;
4202 ItemEMail *email;
4204 if(addrbook.listSelected == NULL)
4205 return;
4207 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4208 if (obj == NULL)
4209 return;
4211 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4212 if(ds == NULL)
4213 return;
4215 iface = ds->interface;
4216 if(! iface->haveLibrary )
4217 return;
4219 person = NULL;
4220 if (obj->type == ADDR_ITEM_EMAIL) {
4221 email = ( ItemEMail * ) obj;
4222 if (email == NULL)
4223 return;
4225 person = (ItemPerson *) ADDRITEM_PARENT(email);
4227 else if (obj->type == ADDR_ITEM_PERSON) {
4228 person = (ItemPerson *) obj;
4230 else {
4231 /* None of these */
4232 return;
4235 if( iface->type == ADDR_IF_LDAP ) {
4236 browseldap_entry(ds, person->externalID);
4239 #endif
4241 /* **********************************************************************
4242 * Build lookup tables.
4243 * ***********************************************************************
4247 * Remap object types.
4248 * Enter: abType AddressObjectType (used in tree node).
4249 * Return: ItemObjectType (used in address cache data).
4251 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4252 ItemObjectType ioType;
4254 switch( abType ) {
4255 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4256 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4257 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4258 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4259 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4260 default: ioType = ITEMTYPE_NONE; break;
4262 return ioType;
4266 * Build table that controls the rendering of object types.
4268 void addrbookctl_build_map( GtkWidget *window ) {
4269 AddressTypeControlItem *atci;
4271 /* Build icons */
4272 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4273 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4274 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4275 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4276 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4277 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4278 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4279 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4280 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4281 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4283 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4284 _addressBookTypeList_ = NULL;
4286 /* Interface */
4287 atci = g_new0( AddressTypeControlItem, 1 );
4288 atci->objectType = ADDR_INTERFACE;
4289 atci->interfaceType = ADDR_IF_NONE;
4290 atci->showInTree = TRUE;
4291 atci->treeExpand = TRUE;
4292 atci->treeLeaf = FALSE;
4293 atci->displayName = _( "Interface" );
4294 atci->iconXpm = folderxpm;
4295 atci->maskXpm = folderxpmmask;
4296 atci->iconXpmOpen = folderopenxpm;
4297 atci->maskXpmOpen = folderopenxpmmask;
4298 atci->menuCommand = NULL;
4299 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4300 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4302 /* Address book */
4303 atci = g_new0( AddressTypeControlItem, 1 );
4304 atci->objectType = ADDR_BOOK;
4305 atci->interfaceType = ADDR_IF_BOOK;
4306 atci->showInTree = TRUE;
4307 atci->treeExpand = TRUE;
4308 atci->treeLeaf = FALSE;
4309 atci->displayName = _( "Address Book" );
4310 atci->iconXpm = bookxpm;
4311 atci->maskXpm = bookxpmmask;
4312 atci->iconXpmOpen = bookxpm;
4313 atci->maskXpmOpen = bookxpmmask;
4314 atci->menuCommand = "/Book/New Book";
4315 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4316 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4318 /* Item person */
4319 atci = g_new0( AddressTypeControlItem, 1 );
4320 atci->objectType = ADDR_ITEM_PERSON;
4321 atci->interfaceType = ADDR_IF_NONE;
4322 atci->showInTree = FALSE;
4323 atci->treeExpand = FALSE;
4324 atci->treeLeaf = FALSE;
4325 atci->displayName = _( "Person" );
4326 atci->iconXpm = NULL;
4327 atci->maskXpm = NULL;
4328 atci->iconXpmOpen = NULL;
4329 atci->maskXpmOpen = NULL;
4330 atci->menuCommand = NULL;
4331 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4332 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4334 /* Item email */
4335 atci = g_new0( AddressTypeControlItem, 1 );
4336 atci->objectType = ADDR_ITEM_EMAIL;
4337 atci->interfaceType = ADDR_IF_NONE;
4338 atci->showInTree = FALSE;
4339 atci->treeExpand = FALSE;
4340 atci->treeLeaf = TRUE;
4341 atci->displayName = _( "EMail Address" );
4342 atci->iconXpm = addressxpm;
4343 atci->maskXpm = addressxpmmask;
4344 atci->iconXpmOpen = addressxpm;
4345 atci->maskXpmOpen = addressxpmmask;
4346 atci->menuCommand = NULL;
4347 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4348 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4350 /* Item group */
4351 atci = g_new0( AddressTypeControlItem, 1 );
4352 atci->objectType = ADDR_ITEM_GROUP;
4353 atci->interfaceType = ADDR_IF_BOOK;
4354 atci->showInTree = TRUE;
4355 atci->treeExpand = FALSE;
4356 atci->treeLeaf = FALSE;
4357 atci->displayName = _( "Group" );
4358 atci->iconXpm = groupxpm;
4359 atci->maskXpm = groupxpmmask;
4360 atci->iconXpmOpen = groupxpm;
4361 atci->maskXpmOpen = groupxpmmask;
4362 atci->menuCommand = NULL;
4363 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4364 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4366 /* Item folder */
4367 atci = g_new0( AddressTypeControlItem, 1 );
4368 atci->objectType = ADDR_ITEM_FOLDER;
4369 atci->interfaceType = ADDR_IF_BOOK;
4370 atci->showInTree = TRUE;
4371 atci->treeExpand = FALSE;
4372 atci->treeLeaf = FALSE;
4373 atci->displayName = _( "Folder" );
4374 atci->iconXpm = folderxpm;
4375 atci->maskXpm = folderxpmmask;
4376 atci->iconXpmOpen = folderopenxpm;
4377 atci->maskXpmOpen = folderopenxpmmask;
4378 atci->menuCommand = NULL;
4379 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4380 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4382 /* vCard */
4383 atci = g_new0( AddressTypeControlItem, 1 );
4384 atci->objectType = ADDR_VCARD;
4385 atci->interfaceType = ADDR_IF_VCARD;
4386 atci->showInTree = TRUE;
4387 atci->treeExpand = TRUE;
4388 atci->treeLeaf = TRUE;
4389 atci->displayName = _( "vCard" );
4390 atci->iconXpm = vcardxpm;
4391 atci->maskXpm = vcardxpmmask;
4392 atci->iconXpmOpen = vcardxpm;
4393 atci->maskXpmOpen = vcardxpmmask;
4394 atci->menuCommand = "/Book/New vCard";
4395 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4396 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4398 /* J-Pilot */
4399 atci = g_new0( AddressTypeControlItem, 1 );
4400 atci->objectType = ADDR_JPILOT;
4401 atci->interfaceType = ADDR_IF_JPILOT;
4402 atci->showInTree = TRUE;
4403 atci->treeExpand = TRUE;
4404 atci->treeLeaf = FALSE;
4405 atci->displayName = _( "JPilot" );
4406 atci->iconXpm = jpilotxpm;
4407 atci->maskXpm = jpilotxpmmask;
4408 atci->iconXpmOpen = jpilotxpm;
4409 atci->maskXpmOpen = jpilotxpmmask;
4410 atci->menuCommand = "/Book/New JPilot";
4411 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4412 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4414 /* Category */
4415 atci = g_new0( AddressTypeControlItem, 1 );
4416 atci->objectType = ADDR_CATEGORY;
4417 atci->interfaceType = ADDR_IF_JPILOT;
4418 atci->showInTree = TRUE;
4419 atci->treeExpand = TRUE;
4420 atci->treeLeaf = TRUE;
4421 atci->displayName = _( "JPilot" );
4422 atci->iconXpm = categoryxpm;
4423 atci->maskXpm = categoryxpmmask;
4424 atci->iconXpmOpen = categoryxpm;
4425 atci->maskXpmOpen = categoryxpmmask;
4426 atci->menuCommand = NULL;
4427 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4428 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4430 /* LDAP Server */
4431 atci = g_new0( AddressTypeControlItem, 1 );
4432 atci->objectType = ADDR_LDAP;
4433 atci->interfaceType = ADDR_IF_LDAP;
4434 atci->showInTree = TRUE;
4435 atci->treeExpand = TRUE;
4436 atci->treeLeaf = FALSE;
4437 atci->displayName = _( "LDAP servers" );
4438 atci->iconXpm = ldapxpm;
4439 atci->maskXpm = ldapxpmmask;
4440 atci->iconXpmOpen = ldapxpm;
4441 atci->maskXpmOpen = ldapxpmmask;
4442 atci->menuCommand = "/Book/New LDAP Server";
4443 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4444 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4446 /* LDAP Query */
4447 atci = g_new0( AddressTypeControlItem, 1 );
4448 atci->objectType = ADDR_LDAP_QUERY;
4449 atci->interfaceType = ADDR_IF_LDAP;
4450 atci->showInTree = TRUE;
4451 atci->treeExpand = FALSE;
4452 atci->treeLeaf = TRUE;
4453 atci->displayName = _( "LDAP Query" );
4454 atci->iconXpm = addrsearchxpm;
4455 atci->maskXpm = addrsearchxpmmask;
4456 atci->iconXpmOpen = addrsearchxpm;
4457 atci->maskXpmOpen = addrsearchxpmmask;
4458 atci->menuCommand = NULL;
4459 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4460 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4465 * Search for specified object type.
4467 AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4468 gint objType = ot;
4469 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4473 * Search for specified interface type.
4475 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4476 GList *node = _addressBookTypeList_;
4477 while( node ) {
4478 AddressTypeControlItem *atci = node->data;
4479 if( atci->interfaceType == ifType ) return atci;
4480 node = g_list_next( node );
4482 return NULL;
4485 static void addrbookctl_free_address( AddressObject *obj ) {
4486 g_free( obj->name );
4487 obj->type = ADDR_NONE;
4488 obj->name = NULL;
4491 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4492 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4493 adapter->interface = NULL;
4494 adapter->interfaceType = ADDR_IF_NONE;
4495 adapter->atci = NULL;
4496 adapter->enabled = FALSE;
4497 adapter->haveLibrary = FALSE;
4498 adapter->treeNode = NULL;
4499 g_free( adapter );
4502 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4503 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4504 adapter->dataSource = NULL;
4505 adapter->subType = ADDR_NONE;
4506 g_free( adapter );
4509 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4510 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4511 adapter->itemFolder = NULL;
4512 g_free( adapter );
4515 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4516 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4517 adapter->itemGroup = NULL;
4518 g_free( adapter );
4522 * Build GUI interface list.
4524 void addrbookctl_build_iflist( void ) {
4525 AddressTypeControlItem *atci;
4526 AdapterInterface *adapter;
4527 GList *list = NULL;
4529 if( _addressIndex_ == NULL ) {
4530 _addressIndex_ = addrindex_create_index();
4531 if( _clipBoard_ == NULL ) {
4532 _clipBoard_ = addrclip_create();
4534 addrclip_set_index( _clipBoard_, _addressIndex_ );
4536 _addressInterfaceList_ = NULL;
4537 list = addrindex_get_interface_list( _addressIndex_ );
4538 while( list ) {
4539 AddressInterface *interface = list->data;
4540 atci = addrbookctl_lookup_iface( interface->type );
4541 if( atci ) {
4542 adapter = g_new0( AdapterInterface, 1 );
4543 adapter->interfaceType = interface->type;
4544 adapter->atci = atci;
4545 adapter->interface = interface;
4546 adapter->treeNode = NULL;
4547 adapter->enabled = TRUE;
4548 adapter->haveLibrary = interface->haveLibrary;
4549 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4550 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4551 _addressInterfaceList_ =
4552 g_list_append( _addressInterfaceList_, adapter );
4554 list = g_list_next( list );
4559 * Find GUI interface type specified interface type.
4560 * \param ifType Interface type.
4561 * \return Interface item, or NULL if not found.
4563 AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4564 GList *node = _addressInterfaceList_;
4565 while( node ) {
4566 AdapterInterface *adapter = node->data;
4567 if( adapter->interfaceType == ifType ) return adapter;
4568 node = g_list_next( node );
4570 return NULL;
4574 * Build interface list selection.
4576 void addrbookctl_build_ifselect( void ) {
4577 GList *newList = NULL;
4578 gchar *selectStr;
4579 gchar **splitStr;
4580 gint ifType;
4581 gint i;
4582 gchar *endptr = NULL;
4583 gboolean enabled;
4584 AdapterInterface *adapter;
4586 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4588 /* Parse string */
4589 splitStr = g_strsplit( selectStr, ",", -1 );
4590 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4591 if( splitStr[i] ) {
4592 /* printf( "%d : %s\n", i, splitStr[i] ); */
4593 ifType = strtol( splitStr[i], &endptr, 10 );
4594 enabled = TRUE;
4595 if( *endptr ) {
4596 if( strcmp( endptr, "/n" ) == 0 ) {
4597 enabled = FALSE;
4600 /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4601 adapter = addrbookctl_find_interface( ifType );
4602 if( adapter ) {
4603 newList = g_list_append( newList, adapter );
4606 else {
4607 break;
4610 /* printf( "i=%d\n", i ); */
4611 g_strfreev( splitStr );
4612 g_free( selectStr );
4614 /* Replace existing list */
4615 mgu_clear_list( _addressIFaceSelection_ );
4616 g_list_free( _addressIFaceSelection_ );
4617 _addressIFaceSelection_ = newList;
4618 newList = NULL;
4621 /* ***********************************************************************
4622 * Add sender to address book.
4623 * ***********************************************************************
4627 * This function is used by the Add sender to address book function.
4629 gboolean addressbook_add_contact(
4630 const gchar *name, const gchar *address, const gchar *remarks )
4632 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4633 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4634 debug_print( "addressbook_add_contact - added\n" );
4635 addressbook_refresh();
4637 return TRUE;
4640 /* ***********************************************************************
4641 * Book/folder selection.
4642 * ***********************************************************************
4646 * This function is used by the matcher dialog to select a book/folder.
4648 gboolean addressbook_folder_selection( gchar **folderpath )
4650 AddressBookFile *book = NULL;
4651 ItemFolder *folder = NULL;
4652 gchar *path;
4654 g_return_val_if_fail( folderpath != NULL, FALSE);
4656 path = *folderpath;
4657 *folderpath = NULL;
4658 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4659 && book != NULL ) {
4660 if ( folder != NULL) {
4661 gchar *tmp = NULL;
4662 gchar *oldtmp = NULL;
4663 AddrItemObject *obj = NULL;
4665 /* walk thru folder->parent to build the full folder path */
4666 /* TODO: wwp: optimize this */
4667 obj = &folder->obj;
4668 tmp = g_strdup(obj->uid);
4669 while ( obj->parent ) {
4670 obj = obj->parent;
4671 if ( obj->name != NULL ) {
4672 oldtmp = g_strdup(tmp);
4673 g_free(tmp);
4674 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4675 g_free(oldtmp);
4678 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4679 g_free(tmp);
4680 } else {
4681 *folderpath = g_strdup_printf("%s", book->fileName);
4683 debug_print( "addressbook_foldersel: %s\n", *folderpath);
4684 return (*folderpath != NULL);
4686 return FALSE;
4689 /* ***********************************************************************
4690 * Book/folder checking.
4691 * ***********************************************************************
4694 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4696 FolderInfo *fi = g_new0( FolderInfo, 1 );
4697 fi->book = abf;
4698 fi->folder = folder;
4699 return fi;
4702 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4703 FolderInfo *fiParent, FolderPathMatch *match )
4705 GList *list;
4706 ItemFolder *folder;
4707 gchar *fName;
4708 FolderInfo *fi;
4709 FolderPathMatch *nextmatch = NULL;
4711 list = parentFolder->listFolder;
4712 while ( list ) {
4713 folder = list->data;
4714 fName = g_strdup( ADDRITEM_NAME(folder) );
4716 /* match folder name, match pointer will be set to NULL if next recursive call
4717 doesn't need to match subfolder name */
4718 if ( match != NULL &&
4719 match->matched == FALSE ) {
4720 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4721 /* folder name matches, prepare next subfolder match */
4722 debug_print("matched folder name '%s'\n", fName);
4723 match->index++;
4724 if ( match->folder_path[match->index] == NULL ) {
4725 /* we've matched all elements */
4726 match->matched = TRUE;
4727 match->folder = folder;
4728 debug_print("book/folder path matched!\n");
4729 } else {
4730 /* keep on matching */
4731 nextmatch = match;
4736 g_free( fName );
4738 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4739 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4740 list = g_list_next( list );
4745 * This function is used by to check if a matcher book/folder path corresponds to an
4746 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4749 gboolean addressbook_peek_folder_exists( gchar *folderpath,
4750 AddressDataSource **book,
4751 ItemFolder **folder )
4753 AddressDataSource *ds;
4754 GList *list, *nodeDS;
4755 ItemFolder *rootFolder;
4756 AddressBookFile *abf;
4757 FolderInfo *fi;
4758 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
4759 FolderPathMatch *nextmatch;
4761 if ( book )
4762 *book = NULL;
4763 if ( folder )
4764 *folder = NULL;
4766 if ( folderpath == NULL )
4767 return FALSE;
4769 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
4770 return TRUE;
4772 /* split the folder path we've received, we'll try to match this path, subpath by
4773 subpath against the book/folder structure in order */
4774 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
4776 list = addrindex_get_interface_list( _addressIndex_ );
4777 while ( list ) {
4778 AddressInterface *interface = list->data;
4779 if ( interface->type == ADDR_IF_BOOK ) {
4780 nodeDS = interface->listSource;
4781 while ( nodeDS ) {
4782 ds = nodeDS->data;
4784 /* Read address book */
4785 if( ! addrindex_ds_get_read_flag( ds ) ) {
4786 addrindex_ds_read_data( ds );
4789 /* Add node for address book */
4790 abf = ds->rawDataSource;
4792 /* try to match subfolders if this book is the right book
4793 (and if there's smth to match, and not yet matched) */
4794 nextmatch = NULL;
4795 if ( folder_path_match.folder_path != NULL &&
4796 folder_path_match.matched == FALSE &&
4797 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
4798 debug_print("matched book name '%s'\n", abf->fileName);
4799 folder_path_match.index = 1;
4800 if ( folder_path_match.folder_path[folder_path_match.index] == NULL ) {
4801 /* we've matched all elements */
4802 folder_path_match.matched = TRUE;
4803 folder_path_match.book = ds;
4804 debug_print("book path matched!\n");
4805 } else {
4806 /* keep on matching */
4807 nextmatch = &folder_path_match;
4811 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
4813 rootFolder = addrindex_ds_get_root_folder( ds );
4814 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, nextmatch );
4816 nodeDS = g_list_next( nodeDS );
4819 list = g_list_next( list );
4822 g_strfreev( folder_path_match.folder_path );
4824 if ( book )
4825 *book = folder_path_match.book;
4826 if ( folder )
4827 *folder = folder_path_match.folder;
4828 return folder_path_match.matched;
4832 /* **********************************************************************
4833 * Address Import.
4834 * ***********************************************************************
4838 * Import LDIF file.
4840 static void addressbook_import_ldif_cb( void ) {
4841 AddressDataSource *ds = NULL;
4842 AdapterDSource *ads = NULL;
4843 AddressBookFile *abf = NULL;
4844 AdapterInterface *adapter;
4845 GtkCTreeNode *newNode;
4847 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4848 if( adapter ) {
4849 if( adapter->treeNode ) {
4850 abf = addressbook_imp_ldif( _addressIndex_ );
4851 if( abf ) {
4852 ds = addrindex_index_add_datasource(
4853 _addressIndex_, ADDR_IF_BOOK, abf );
4854 ads = addressbook_create_ds_adapter(
4855 ds, ADDR_BOOK, NULL );
4856 addressbook_ads_set_name(
4857 ads, addrbook_get_name( abf ) );
4858 newNode = addressbook_add_object(
4859 adapter->treeNode,
4860 ADDRESS_OBJECT(ads) );
4861 if( newNode ) {
4862 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4863 newNode );
4864 addrbook.treeSelected = newNode;
4867 /* Notify address completion */
4868 invalidate_address_completion();
4875 * Import MUTT file.
4877 static void addressbook_import_mutt_cb( void ) {
4878 AddressDataSource *ds = NULL;
4879 AdapterDSource *ads = NULL;
4880 AddressBookFile *abf = NULL;
4881 AdapterInterface *adapter;
4882 GtkCTreeNode *newNode;
4884 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4885 if( adapter ) {
4886 if( adapter->treeNode ) {
4887 abf = addressbook_imp_mutt( _addressIndex_ );
4888 if( abf ) {
4889 ds = addrindex_index_add_datasource(
4890 _addressIndex_, ADDR_IF_BOOK, abf );
4891 ads = addressbook_create_ds_adapter(
4892 ds, ADDR_BOOK, NULL );
4893 addressbook_ads_set_name(
4894 ads, addrbook_get_name( abf ) );
4895 newNode = addressbook_add_object(
4896 adapter->treeNode,
4897 ADDRESS_OBJECT(ads) );
4898 if( newNode ) {
4899 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4900 newNode );
4901 addrbook.treeSelected = newNode;
4904 /* Notify address completion */
4905 invalidate_address_completion();
4912 * Import Pine file.
4914 static void addressbook_import_pine_cb( void ) {
4915 AddressDataSource *ds = NULL;
4916 AdapterDSource *ads = NULL;
4917 AddressBookFile *abf = NULL;
4918 AdapterInterface *adapter;
4919 GtkCTreeNode *newNode;
4921 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4922 if( adapter ) {
4923 if( adapter->treeNode ) {
4924 abf = addressbook_imp_pine( _addressIndex_ );
4925 if( abf ) {
4926 ds = addrindex_index_add_datasource(
4927 _addressIndex_, ADDR_IF_BOOK, abf );
4928 ads = addressbook_create_ds_adapter(
4929 ds, ADDR_BOOK, NULL );
4930 addressbook_ads_set_name(
4931 ads, addrbook_get_name( abf ) );
4932 newNode = addressbook_add_object(
4933 adapter->treeNode,
4934 ADDRESS_OBJECT(ads) );
4935 if( newNode ) {
4936 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4937 newNode );
4938 addrbook.treeSelected = newNode;
4941 /* Notify address completion */
4942 invalidate_address_completion();
4949 * Harvest addresses.
4950 * \param folderItem Folder to import.
4951 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
4952 * \param msgList List of message numbers, or NULL to process folder.
4954 void addressbook_harvest(
4955 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
4957 AddressDataSource *ds = NULL;
4958 AdapterDSource *ads = NULL;
4959 AddressBookFile *abf = NULL;
4960 AdapterInterface *adapter;
4961 GtkCTreeNode *newNode;
4963 abf = addrgather_dlg_execute(
4964 folderItem, _addressIndex_, sourceInd, msgList );
4965 if( abf ) {
4966 ds = addrindex_index_add_datasource(
4967 _addressIndex_, ADDR_IF_BOOK, abf );
4969 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4970 if( adapter ) {
4971 if( adapter->treeNode ) {
4972 ads = addressbook_create_ds_adapter(
4973 ds, ADDR_BOOK, addrbook_get_name( abf ) );
4974 newNode = addressbook_add_object(
4975 adapter->treeNode,
4976 ADDRESS_OBJECT(ads) );
4980 /* Notify address completion */
4981 invalidate_address_completion();
4986 * Export HTML file.
4988 static void addressbook_export_html_cb( void ) {
4989 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4990 AddressObject *obj;
4991 AddressDataSource *ds = NULL;
4992 AddrBookBase *adbase;
4993 AddressCache *cache;
4994 GtkCTreeNode *node = NULL;
4996 if( ! addrbook.treeSelected ) return;
4997 node = addrbook.treeSelected;
4998 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4999 obj = gtk_ctree_node_get_row_data( ctree, node );
5000 if( obj == NULL ) return;
5002 ds = addressbook_find_datasource( node );
5003 if( ds == NULL ) return;
5004 adbase = ( AddrBookBase * ) ds->rawDataSource;
5005 cache = adbase->addressCache;
5006 addressbook_exp_html( cache );
5010 * Export LDIF file.
5012 static void addressbook_export_ldif_cb( void ) {
5013 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5014 AddressObject *obj;
5015 AddressDataSource *ds = NULL;
5016 AddrBookBase *adbase;
5017 AddressCache *cache;
5018 GtkCTreeNode *node = NULL;
5020 if( ! addrbook.treeSelected ) return;
5021 node = addrbook.treeSelected;
5022 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5023 obj = gtk_ctree_node_get_row_data( ctree, node );
5024 if( obj == NULL ) return;
5026 ds = addressbook_find_datasource( node );
5027 if( ds == NULL ) return;
5028 adbase = ( AddrBookBase * ) ds->rawDataSource;
5029 cache = adbase->addressCache;
5030 addressbook_exp_ldif( cache );
5033 static void addressbook_start_drag(GtkWidget *widget, gint button,
5034 GdkEvent *event,
5035 void *data)
5037 GdkDragContext *context;
5038 if (addressbook_target_list == NULL)
5039 addressbook_target_list = gtk_target_list_new(
5040 addressbook_drag_types, 1);
5041 context = gtk_drag_begin(widget, addressbook_target_list,
5042 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5043 gtk_drag_set_icon_default(context);
5046 static void addressbook_drag_data_get(GtkWidget *widget,
5047 GdkDragContext *drag_context,
5048 GtkSelectionData *selection_data,
5049 guint info,
5050 guint time,
5051 void *data)
5053 AddrItemObject *aio = NULL;
5054 AddressObject *pobj = NULL;
5055 AdapterDSource *ads = NULL;
5056 AddressDataSource *ds = NULL;
5057 GList *cur;
5059 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5061 if( pobj == NULL ) return;
5063 if( pobj->type == ADDR_DATASOURCE ) {
5064 ads = ADAPTER_DSOURCE(pobj);
5065 ds = ads->dataSource;
5066 } else if (pobj->type == ADDR_ITEM_GROUP) {
5068 return;
5071 else if( pobj->type != ADDR_INTERFACE ) {
5072 ds = addressbook_find_datasource( addrbook.treeSelected );
5074 if (!ds)
5075 return;
5078 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5079 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5080 GTK_CTREE_NODE(cur->data));
5081 while (aio && aio->type != ADDR_ITEM_PERSON) {
5082 aio = aio->parent;
5086 if (aio && aio->type == ADDR_ITEM_PERSON) {
5087 if( ds && ds->interface && ds->interface->readOnly)
5088 gtk_selection_data_set(selection_data,
5089 selection_data->target, 8,
5090 "Dummy_addr_copy", 15);
5091 else
5092 gtk_selection_data_set(selection_data,
5093 selection_data->target, 8,
5094 "Dummy_addr_move", 15);
5098 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5099 GdkDragContext *context,
5100 gint x,
5101 gint y,
5102 guint time,
5103 void *data)
5105 gint row, column;
5106 GtkCTreeNode *node = NULL;
5107 gboolean acceptable = FALSE;
5108 gint height = addrbook.ctree->allocation.height;
5109 gint total_height = addrbook.ctree->requisition.height;
5110 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5111 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5112 gfloat vpos = pos->value;
5114 if (gtk_clist_get_selection_info
5115 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5117 if (y > height - 24 && height + vpos < total_height)
5118 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5120 if (y < 24 && y > 0)
5121 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5123 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5125 if (node != NULL) {
5126 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5127 if( obj->type == ADDR_ITEM_FOLDER
5128 || obj->type == ADDR_ITEM_GROUP)
5129 acceptable = TRUE;
5130 else {
5131 AdapterDSource *ads = NULL;
5132 AddressDataSource *ds = NULL;
5133 ads = ADAPTER_DSOURCE(obj);
5134 if (ads == NULL ){ return FALSE;}
5135 ds = ads->dataSource;
5136 if (ds == NULL ) { return FALSE;}
5138 acceptable = TRUE;
5143 if (acceptable) {
5144 g_signal_handlers_block_by_func
5145 (G_OBJECT(widget),
5146 G_CALLBACK(addressbook_tree_selected), NULL);
5147 gtk_sctree_select( GTK_SCTREE(widget), node);
5148 g_signal_handlers_unblock_by_func
5149 (G_OBJECT(widget),
5150 G_CALLBACK(addressbook_tree_selected), NULL);
5151 gdk_drag_status(context,
5152 (context->actions == GDK_ACTION_COPY ?
5153 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5154 } else {
5155 gdk_drag_status(context, 0, time);
5158 return acceptable;
5161 static void addressbook_drag_leave_cb(GtkWidget *widget,
5162 GdkDragContext *context,
5163 guint time,
5164 void *data)
5166 if (addrbook.treeSelected) {
5167 g_signal_handlers_block_by_func
5168 (G_OBJECT(widget),
5169 G_CALLBACK(addressbook_tree_selected), NULL);
5170 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5171 g_signal_handlers_unblock_by_func
5172 (G_OBJECT(widget),
5173 G_CALLBACK(addressbook_tree_selected), NULL);
5178 static void addressbook_drag_received_cb(GtkWidget *widget,
5179 GdkDragContext *drag_context,
5180 gint x,
5181 gint y,
5182 GtkSelectionData *data,
5183 guint info,
5184 guint time,
5185 void *pdata)
5187 gint row, column;
5188 GtkCTreeNode *node;
5189 GtkCTreeNode *lastopened = addrbook.opened;
5191 if (!strncmp(data->data, "Dummy_addr", 10)) {
5192 if (gtk_clist_get_selection_info
5193 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5194 return;
5197 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5198 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5199 return;
5201 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5202 if (drag_context->action == GDK_ACTION_COPY ||
5203 !strcmp(data->data, "Dummy_addr_copy"))
5204 addressbook_clip_copy_cb();
5205 else
5206 addressbook_clip_cut_cb();
5207 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5208 addressbook_clip_paste_cb();
5209 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5210 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5211 gtk_drag_finish(drag_context, TRUE, TRUE, time);
5216 * End of Source.