2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2012 Match Grun 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 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Add address to address book dialog.
26 #include "claws-features.h"
32 #include <glib/gi18n.h>
33 #include <gdk/gdkkeysyms.h>
37 #include "stock_pixmap.h"
38 #include "prefs_common.h"
39 #include "prefs_gtk.h"
40 #include "addressadd.h"
41 #ifndef USE_ALT_ADDRBOOK
44 #include "addrindex.h"
45 #include "ldapserver.h"
46 #include "ldapupdate.h"
48 #include "addressbook-dbus.h"
50 #include "manage_window.h"
51 #include "alertpanel.h"
53 #ifndef USE_ALT_ADDRBOOK
55 AddressBookFile
*book
;
64 static struct _AddressAdd_dlg
{
67 GtkWidget
*entry_name
;
68 GtkWidget
*label_address
;
69 GtkWidget
*entry_remarks
;
70 GtkWidget
*tree_folder
;
72 GtkWidget
*cancel_btn
;
73 FolderInfo
*fiSelected
;
76 static GdkPixbuf
*folderXpm
;
77 static GdkPixbuf
*bookXpm
;
79 static gboolean addressadd_cancelled
;
88 #ifndef USE_ALT_ADDRBOOK
89 static FolderInfo
*addressadd_create_folderinfo( AddressBookFile
*abf
, ItemFolder
*folder
)
91 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
97 static FolderInfo
*addressadd_create_folderinfo(gchar
* book
) {
98 FolderInfo
*fi
= g_new0( FolderInfo
, 1 );
104 #ifndef USE_ALT_ADDRBOOK
105 static void addressadd_free_folderinfo( FolderInfo
*fi
) {
111 static void addressadd_free_folderinfo( FolderInfo
*fi
) {
117 static gint
addressadd_delete_event( GtkWidget
*widget
, GdkEventAny
*event
, gboolean
*cancelled
) {
118 addressadd_cancelled
= TRUE
;
123 static gboolean
addressadd_key_pressed( GtkWidget
*widget
, GdkEventKey
*event
, gboolean
*cancelled
) {
124 if (event
&& event
->keyval
== GDK_KEY_Escape
) {
125 addressadd_cancelled
= TRUE
;
131 /* Points addressadd_dlg.fiSelected to the selected item */
132 static void set_selected_ptr()
134 addressadd_dlg
.fiSelected
= gtkut_tree_view_get_selected_pointer(
135 GTK_TREE_VIEW(addressadd_dlg
.tree_folder
), ADDRADD_COL_PTR
,
139 static void addressadd_ok( GtkWidget
*widget
, gboolean
*cancelled
) {
141 addressadd_cancelled
= FALSE
;
145 static void addressadd_cancel( GtkWidget
*widget
, gboolean
*cancelled
) {
147 addressadd_cancelled
= TRUE
;
151 static void addressadd_tree_row_activated(GtkTreeView
*view
,
152 GtkTreePath
*path
, GtkTreeViewColumn
*col
,
155 addressadd_ok(NULL
, NULL
);
158 static void addressadd_size_allocate_cb(GtkWidget
*widget
,
159 GtkAllocation
*allocation
)
161 cm_return_if_fail(allocation
!= NULL
);
163 prefs_common
.addressaddwin_width
= allocation
->width
;
164 prefs_common
.addressaddwin_height
= allocation
->height
;
167 static void addressadd_create( void ) {
169 GtkWidget
*vbox
, *hbox
;
174 GtkWidget
*entry_name
;
175 GtkWidget
*label_addr
;
176 GtkWidget
*entry_rems
;
177 GtkWidget
*tree_folder
;
182 GtkWidget
*cancel_btn
;
184 static GdkGeometry geometry
;
186 GtkTreeViewColumn
*col
;
187 GtkCellRenderer
*rdr
;
188 GtkTreeSelection
*sel
;
190 window
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "addressadd");
191 gtk_container_set_border_width( GTK_CONTAINER(window
), VBOX_BORDER
);
192 gtk_window_set_title( GTK_WINDOW(window
), _("Add to address book") );
193 gtk_window_set_position( GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
194 gtk_window_set_type_hint(GTK_WINDOW(window
), GDK_WINDOW_TYPE_HINT_DIALOG
);
195 g_signal_connect( G_OBJECT(window
), "delete_event",
196 G_CALLBACK(addressadd_delete_event
), NULL
);
197 g_signal_connect( G_OBJECT(window
), "key_press_event",
198 G_CALLBACK(addressadd_key_pressed
), NULL
);
199 g_signal_connect(G_OBJECT(window
), "size_allocate",
200 G_CALLBACK(addressadd_size_allocate_cb
), NULL
);
202 hbox
= gtk_hbox_new(FALSE
, 10);
203 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 4);
204 vbox
= gtk_vbox_new(FALSE
, 8);
205 gtk_container_add(GTK_CONTAINER(window
), vbox
);
207 picture
= gtk_image_new();
208 gtk_box_pack_start(GTK_BOX(hbox
), picture
, FALSE
, FALSE
, 0);
210 table
= gtk_table_new(3, 2, FALSE
);
211 gtk_box_pack_start(GTK_BOX(hbox
), table
, TRUE
, TRUE
, 0);
212 gtk_table_set_row_spacings(GTK_TABLE(table
), VSPACING_NARROW
);
213 gtk_table_set_col_spacings(GTK_TABLE(table
), HSPACING_NARROW
);
215 frame
= gtk_frame_new(_("Contact"));
216 gtk_frame_set_label_align(GTK_FRAME(frame
), 0.01, 0.5);
217 gtk_container_add(GTK_CONTAINER(frame
), hbox
);
218 gtk_container_set_border_width( GTK_CONTAINER(frame
), 4);
219 gtk_box_pack_start(GTK_BOX(vbox
), frame
, FALSE
, FALSE
, 0);
223 label
= gtk_label_new(_("Name"));
224 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
225 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
227 entry_name
= gtk_entry_new();
228 gtk_widget_set_size_request(entry_name
, 150, -1);
229 gtk_entry_set_text (GTK_ENTRY(entry_name
),"");
231 gtk_table_attach(GTK_TABLE(table
), entry_name
, 1, 2, top
, (top
+ 1), GTK_FILL
| GTK_EXPAND
, 0, 0, 0);
235 label
= gtk_label_new(_("Address"));
236 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
237 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
239 label_addr
= gtk_label_new("");
240 gtk_widget_set_size_request(label_addr
, 150, -1);
241 gtk_table_attach(GTK_TABLE(table
), label_addr
, 1, 2, top
, (top
+ 1), GTK_FILL
| GTK_EXPAND
, 0, 0, 0);
242 gtk_misc_set_alignment(GTK_MISC(label_addr
), 0, 0.5);
246 label
= gtk_label_new(_("Remarks"));
247 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
248 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
250 entry_rems
= gtk_entry_new();
251 gtk_widget_set_size_request(entry_rems
, 150, -1);
252 gtk_table_attach(GTK_TABLE(table
), entry_rems
, 1, 2, top
, (top
+ 1), GTK_FILL
| GTK_EXPAND
, 0, 0, 0);
254 /* Address book/folder tree */
255 vlbox
= gtk_vbox_new(FALSE
, VBOX_BORDER
);
256 gtk_box_pack_start(GTK_BOX(vbox
), vlbox
, TRUE
, TRUE
, 0);
257 gtk_container_set_border_width( GTK_CONTAINER(vlbox
), 4);
259 tree_win
= gtk_scrolled_window_new( NULL
, NULL
);
260 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win
),
261 GTK_POLICY_AUTOMATIC
,
262 GTK_POLICY_AUTOMATIC
);
263 gtk_box_pack_start( GTK_BOX(vlbox
), tree_win
, TRUE
, TRUE
, 0 );
265 store
= gtk_tree_store_new(N_ADDRADD_COLS
,
266 GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_POINTER
);
268 tree_folder
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
269 g_object_unref(store
);
270 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
), ADDRADD_COL_NAME
, GTK_SORT_ASCENDING
);
271 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_folder
), prefs_common
.use_stripes_everywhere
);
272 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_folder
), TRUE
);
273 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(tree_folder
), FALSE
);
274 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree_folder
),
277 /* Column with addressbook/folder icon and name. It has two
278 * renderers, so we create it a bit differently. */
279 col
= gtk_tree_view_column_new();
280 rdr
= gtk_cell_renderer_pixbuf_new();
281 gtk_cell_renderer_set_padding(rdr
, 0, 0);
282 gtk_tree_view_column_pack_start(col
, rdr
, FALSE
);
283 gtk_tree_view_column_set_attributes(col
, rdr
,
284 "pixbuf", ADDRADD_COL_ICON
, NULL
);
285 rdr
= gtk_cell_renderer_text_new();
286 gtk_tree_view_column_pack_start(col
, rdr
, TRUE
);
287 gtk_tree_view_column_set_attributes(col
, rdr
,
288 "markup", ADDRADD_COL_NAME
, NULL
);
289 gtk_tree_view_column_set_title(col
, _("Select Address Book Folder"));
290 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_folder
), col
);
292 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_folder
));
293 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_BROWSE
);
295 gtk_container_add( GTK_CONTAINER(tree_win
), tree_folder
);
297 g_signal_connect(G_OBJECT(tree_folder
), "row-activated",
298 G_CALLBACK(addressadd_tree_row_activated
), NULL
);
301 gtkut_stock_button_set_create(&hbbox
, &cancel_btn
, GTK_STOCK_CANCEL
,
302 &ok_btn
, GTK_STOCK_OK
,
304 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
305 gtk_container_set_border_width( GTK_CONTAINER(hbbox
), HSPACING_NARROW
);
306 gtk_widget_grab_default(ok_btn
);
308 g_signal_connect(G_OBJECT(ok_btn
), "clicked",
309 G_CALLBACK(addressadd_ok
), NULL
);
310 g_signal_connect(G_OBJECT(cancel_btn
), "clicked",
311 G_CALLBACK(addressadd_cancel
), NULL
);
313 if (!geometry
.min_height
) {
314 geometry
.min_width
= 300;
315 geometry
.min_height
= 350;
318 gtk_window_set_geometry_hints(GTK_WINDOW(window
), NULL
, &geometry
,
320 gtk_widget_set_size_request(window
, prefs_common
.addressaddwin_width
,
321 prefs_common
.addressaddwin_height
);
323 addressadd_dlg
.window
= window
;
324 addressadd_dlg
.picture
= picture
;
325 addressadd_dlg
.entry_name
= entry_name
;
326 addressadd_dlg
.label_address
= label_addr
;
327 addressadd_dlg
.entry_remarks
= entry_rems
;
328 addressadd_dlg
.tree_folder
= tree_folder
;
329 addressadd_dlg
.ok_btn
= ok_btn
;
330 addressadd_dlg
.cancel_btn
= cancel_btn
;
332 gtk_widget_show_all( window
);
334 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK
, &bookXpm
);
335 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderXpm
);
338 /* Helper function used by addressadd_tree_clear(). */
339 static gboolean
close_dialog_foreach_func(GtkTreeModel
*model
,
346 gtk_tree_model_get(model
, iter
, ADDRADD_COL_PTR
, &fi
, -1);
348 addressadd_free_folderinfo(fi
);
350 gtk_tree_store_set(GTK_TREE_STORE(model
), iter
, ADDRADD_COL_PTR
, NULL
, -1);
354 /* Function to remove all rows from the tree view, and free the
355 * FolderInfo pointers in them in pointer column. */
356 static void addressadd_tree_clear()
358 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
359 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
361 gtk_tree_model_foreach(model
, close_dialog_foreach_func
, NULL
);
362 gtk_tree_store_clear(GTK_TREE_STORE(model
));
365 #ifndef USE_ALT_ADDRBOOK
366 static void addressadd_load_folder( GtkTreeIter
*parent_iter
,
367 ItemFolder
*parentFolder
, FolderInfo
*fiParent
)
369 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
371 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
377 list
= parentFolder
->listFolder
;
380 name
= g_strdup( ADDRITEM_NAME(folder
) );
381 fi
= addressadd_create_folderinfo( fiParent
->book
, folder
);
383 gtk_tree_store_append(GTK_TREE_STORE(model
), &iter
, parent_iter
);
384 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
,
385 ADDRADD_COL_ICON
, folderXpm
,
386 ADDRADD_COL_NAME
, name
,
391 addressadd_load_folder( parent_iter
, folder
, fi
);
393 list
= g_list_next( list
);
397 static void addressadd_load_data( AddressIndex
*addrIndex
) {
398 AddressDataSource
*ds
;
399 GList
*list
, *nodeDS
;
401 ItemFolder
*rootFolder
;
402 AddressBookFile
*abf
;
404 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
406 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
407 GtkTreeSelection
*sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(view
));
409 addressadd_tree_clear();
411 list
= addrindex_get_interface_list( addrIndex
);
413 AddressInterface
*ainterface
= list
->data
;
414 if( ainterface
->type
== ADDR_IF_BOOK
||
415 ainterface
->type
== ADDR_IF_LDAP
) {
416 nodeDS
= ainterface
->listSource
;
419 name
= g_strdup( addrindex_ds_get_name( ds
) );
421 /* Read address book */
422 if( ! addrindex_ds_get_read_flag( ds
) ) {
423 addrindex_ds_read_data( ds
);
426 /* Add node for address book */
427 abf
= ds
->rawDataSource
;
428 fi
= addressadd_create_folderinfo( abf
, NULL
);
430 gtk_tree_store_append(GTK_TREE_STORE(model
), &iter
, NULL
);
431 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
,
432 ADDRADD_COL_ICON
, bookXpm
,
433 ADDRADD_COL_NAME
, name
,
438 rootFolder
= addrindex_ds_get_root_folder( ds
);
439 addressadd_load_folder( &iter
, rootFolder
, fi
);
441 nodeDS
= g_list_next( nodeDS
);
444 list
= g_list_next( list
);
447 if (gtk_tree_model_get_iter_first(model
, &iter
))
448 gtk_tree_selection_select_iter(sel
, &iter
);
451 static void addressadd_load_data() {
453 FolderInfo
*fi
= NULL
;
454 GError
* error
= NULL
;
455 GtkWidget
*view
= addressadd_dlg
.tree_folder
;
457 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(view
));
458 GtkTreeSelection
*sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(view
));
461 addressadd_tree_clear();
463 list
= addressbook_dbus_get_books(&error
);
464 for (; list
; list
= g_slist_next(list
)) {
465 name
= (gchar
*) list
->data
;
466 fi
= addressadd_create_folderinfo(name
);
467 gtk_tree_store_append(GTK_TREE_STORE(model
), &iter
, NULL
);
468 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
,
469 ADDRADD_COL_ICON
, bookXpm
,ADDRADD_COL_NAME
, (gchar
*)list
->data
,
474 if (gtk_tree_model_get_iter_first(model
, &iter
))
475 gtk_tree_selection_select_iter(sel
, &iter
);
479 #ifndef USE_ALT_ADDRBOOK
480 gboolean
addressadd_selection( AddressIndex
*addrIndex
, const gchar
*name
,
481 const gchar
*address
, const gchar
*remarks
, GdkPixbuf
*picture
) {
483 gboolean
addressadd_selection(const gchar
*name
, const gchar
*address
,
484 const gchar
*remarks
, GdkPixbuf
*picture
) {
486 gboolean retVal
= FALSE
;
487 #ifndef USE_ALT_ADDRBOOK
488 ItemPerson
*person
= NULL
;
490 FolderInfo
*fi
= NULL
;
491 addressadd_cancelled
= FALSE
;
493 if( ! addressadd_dlg
.window
) addressadd_create();
495 addressadd_dlg
.fiSelected
= NULL
;
496 #ifndef USE_ALT_ADDRBOOK
497 addressadd_load_data( addrIndex
);
499 addressadd_load_data();
501 gtk_widget_show(addressadd_dlg
.window
);
502 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), TRUE
);
503 gtk_widget_grab_focus(addressadd_dlg
.ok_btn
);
505 manage_window_set_transient(GTK_WINDOW(addressadd_dlg
.window
));
507 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), "" );
508 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), "" );
509 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), "" );
511 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_name
), name
);
513 gtk_label_set_text( GTK_LABEL(addressadd_dlg
.label_address
), address
);
515 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg
.entry_remarks
), remarks
);
517 gtk_image_set_from_pixbuf(GTK_IMAGE(addressadd_dlg
.picture
), picture
);
518 gtk_widget_show(GTK_WIDGET(addressadd_dlg
.picture
));
520 gtk_widget_hide(GTK_WIDGET(addressadd_dlg
.picture
));
523 gtk_widget_hide( addressadd_dlg
.window
);
524 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg
.window
), FALSE
);
525 if( ! addressadd_cancelled
) {
526 if( addressadd_dlg
.fiSelected
) {
527 gchar
*returned_name
;
528 gchar
*returned_remarks
;
529 returned_name
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_name
), 0, -1 );
530 returned_remarks
= gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg
.entry_remarks
), 0, -1 );
532 fi
= addressadd_dlg
.fiSelected
;
534 #ifndef USE_ALT_ADDRBOOK
535 person
= addrbook_add_contact( fi
->book
, fi
->folder
,
540 if (person
!= NULL
) {
541 person
->status
= ADD_ENTRY
;
544 GError
*error
= NULL
;
545 gchar
*name
= g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S
, ADDRBOOK_DIR
, G_DIR_SEPARATOR_S
,
546 ADDRITEM_ID(person
), ".png", NULL
);
547 gdk_pixbuf_save(picture
, name
, "png", &error
, NULL
);
549 g_warning("Failed to save image: %s",
553 addritem_person_set_picture( person
, ADDRITEM_ID(person
) ) ;
558 ContactData
* contact
= g_new0(ContactData
, 1);
559 GError
* error
= NULL
;
562 contact
->cn
= g_strdup(returned_name
);
564 contact
->cn
= g_strdup(address
);
566 contact
->name
= g_strdup(returned_name
);
567 contact
->email
= g_strdup(address
);
568 contact
->remarks
= g_strdup(returned_remarks
);
569 contact
->book
= g_strdup(fi
->book
);
570 contact
->picture
= picture
;
572 if (addressbook_dbus_add_contact(contact
, &error
) == 0) {
573 debug_print("Added to addressbook:\n%s\n%s\n%s\n%s\n",
574 returned_name
, address
, returned_remarks
, fi
->book
);
580 GtkWidget
* dialog
= gtk_message_dialog_new (
581 GTK_WINDOW(addressadd_dlg
.window
),
582 GTK_DIALOG_DESTROY_WITH_PARENT
,
585 "%s", error
->message
);
586 gtk_dialog_run (GTK_DIALOG (dialog
));
587 gtk_widget_destroy (dialog
);
591 contact_data_free(&contact
);
594 if (person
!= NULL
&& fi
->book
->type
== ADBOOKTYPE_LDAP
) {
595 LdapServer
*server
= (LdapServer
*) fi
->book
;
596 ldapsvr_set_modified(server
, TRUE
);
597 ldapsvr_update_book(server
, person
);
598 if (server
->retVal
!= LDAPRC_SUCCESS
) {
599 alertpanel( _("Add address(es)"),
600 _("Can't add the specified address"),
601 GTK_STOCK_CLOSE
, NULL
, NULL
, ALERTFOCUS_FIRST
);
602 return server
->retVal
;
606 g_free(returned_name
);
607 g_free(returned_remarks
);
608 #ifndef USE_ALT_ADDRBOOK
609 if( person
) retVal
= TRUE
;
614 addressadd_tree_clear();