addressadd.c (15033B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 2001-2024 the Claws Mail team and Match Grun 4 * 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. 9 * 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. 14 * 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/>. 17 */ 18 19 /* 20 * Add address to address book dialog. 21 */ 22 23 #include "defs.h" 24 25 #include <glib.h> 26 #include <glib/gi18n.h> 27 #include <gdk/gdkkeysyms.h> 28 #include <gtk/gtk.h> 29 30 #include "gtkutils.h" 31 #include "stock_pixmap.h" 32 #include "prefs_common.h" 33 #include "prefs_gtk.h" 34 #include "addressadd.h" 35 #include "addritem.h" 36 #include "addrbook.h" 37 #include "addrindex.h" 38 #include "manage_window.h" 39 #include "alertpanel.h" 40 41 typedef struct { 42 AddressBookFile *book; 43 ItemFolder *folder; 44 } FolderInfo; 45 46 static struct _AddressAdd_dlg { 47 GtkWidget *window; 48 GtkWidget *picture; 49 GtkWidget *entry_name; 50 GtkWidget *label_address; 51 GtkWidget *entry_remarks; 52 GtkWidget *tree_folder; 53 GtkWidget *ok_btn; 54 GtkWidget *cancel_btn; 55 FolderInfo *fiSelected; 56 } addressadd_dlg; 57 58 static GdkPixbuf *folderXpm; 59 static GdkPixbuf *bookXpm; 60 61 static gboolean addressadd_cancelled; 62 63 enum { 64 ADDRADD_COL_ICON, 65 ADDRADD_COL_NAME, 66 ADDRADD_COL_PTR, 67 N_ADDRADD_COLS 68 }; 69 70 static FolderInfo *addressadd_create_folderinfo( AddressBookFile *abf, ItemFolder *folder ) 71 { 72 FolderInfo *fi = g_new0( FolderInfo, 1 ); 73 fi->book = abf; 74 fi->folder = folder; 75 return fi; 76 } 77 78 static void addressadd_free_folderinfo( FolderInfo *fi ) { 79 fi->book = NULL; 80 fi->folder = NULL; 81 g_free( fi ); 82 } 83 84 static gint addressadd_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled ) { 85 addressadd_cancelled = TRUE; 86 gtk_main_quit(); 87 return TRUE; 88 } 89 90 /* Points addressadd_dlg.fiSelected to the selected item */ 91 static void set_selected_ptr() 92 { 93 addressadd_dlg.fiSelected = gtkut_tree_view_get_selected_pointer( 94 GTK_TREE_VIEW(addressadd_dlg.tree_folder), ADDRADD_COL_PTR, 95 NULL, NULL, NULL); 96 } 97 98 static void addressadd_ok( GtkWidget *widget, gboolean *cancelled ) { 99 set_selected_ptr(); 100 addressadd_cancelled = FALSE; 101 gtk_main_quit(); 102 } 103 104 static void addressadd_cancel( GtkWidget *widget, gboolean *cancelled ) { 105 set_selected_ptr(); 106 addressadd_cancelled = TRUE; 107 gtk_main_quit(); 108 } 109 110 static void addressadd_tree_row_activated(GtkTreeView *view, 111 GtkTreePath *path, GtkTreeViewColumn *col, 112 gpointer user_data) 113 { 114 addressadd_ok(NULL, NULL); 115 } 116 117 static void addressadd_size_allocate_cb(GtkWidget *widget, 118 GtkAllocation *allocation) 119 { 120 cm_return_if_fail(allocation != NULL); 121 122 gtk_window_get_size(GTK_WINDOW(widget), 123 &prefs_common.addressaddwin_width, &prefs_common.addressaddwin_height); 124 } 125 126 static void addressadd_create( void ) { 127 GtkWidget *window; 128 GtkWidget *vbox, *hbox; 129 GtkWidget *frame; 130 GtkWidget *table; 131 GtkWidget *label; 132 GtkWidget *picture; 133 GtkWidget *entry_name; 134 GtkWidget *label_addr; 135 GtkWidget *entry_rems; 136 GtkWidget *tree_folder; 137 GtkWidget *vlbox; 138 GtkWidget *tree_win; 139 GtkWidget *hbbox; 140 GtkWidget *ok_btn; 141 GtkWidget *cancel_btn; 142 static GdkGeometry geometry; 143 GtkTreeStore *store; 144 GtkTreeViewColumn *col; 145 GtkCellRenderer *rdr; 146 GtkTreeSelection *sel; 147 148 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressadd"); 149 gtk_container_set_border_width( GTK_CONTAINER(window), VBOX_BORDER ); 150 gtk_window_set_title( GTK_WINDOW(window), _("Add to address book") ); 151 gtk_window_set_position( GTK_WINDOW(window), GTK_WIN_POS_MOUSE ); 152 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG); 153 g_signal_connect( G_OBJECT(window), "delete_event", 154 G_CALLBACK(addressadd_delete_event), NULL ); 155 g_signal_connect(G_OBJECT(window), "size_allocate", 156 G_CALLBACK(addressadd_size_allocate_cb), NULL); 157 158 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); 159 gtk_container_set_border_width(GTK_CONTAINER(hbox), 4); 160 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); 161 gtk_container_add(GTK_CONTAINER(window), vbox); 162 163 picture = gtk_image_new(); 164 gtk_box_pack_start(GTK_BOX(hbox), picture, FALSE, FALSE, 0); 165 166 table = gtk_grid_new(); 167 gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0); 168 gtk_grid_set_row_spacing(GTK_GRID(table), VSPACING_NARROW); 169 gtk_grid_set_column_spacing(GTK_GRID(table), HSPACING_NARROW); 170 171 frame = gtk_frame_new(_("Contact")); 172 gtk_frame_set_label_align(GTK_FRAME(frame), 0.01, 0.5); 173 gtk_container_add(GTK_CONTAINER(frame), hbox); 174 gtk_container_set_border_width( GTK_CONTAINER(frame), 4); 175 gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); 176 177 /* First row */ 178 label = gtk_label_new(_("Name")); 179 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1); 180 gtk_label_set_xalign(GTK_LABEL(label), 0.0); 181 182 entry_name = gtk_entry_new(); 183 gtk_widget_set_size_request(entry_name, 150, -1); 184 gtk_entry_set_text (GTK_ENTRY(entry_name),""); 185 186 gtk_grid_attach(GTK_GRID(table), entry_name, 1, 0, 1, 1); 187 gtk_widget_set_hexpand(entry_name, TRUE); 188 gtk_widget_set_halign(entry_name, GTK_ALIGN_FILL); 189 190 /* Second row */ 191 label = gtk_label_new(_("Address")); 192 gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1); 193 gtk_label_set_xalign(GTK_LABEL(label), 0.0); 194 195 label_addr = gtk_label_new(""); 196 gtk_widget_set_size_request(label_addr, 150, -1); 197 gtk_grid_attach(GTK_GRID(table), label_addr, 1, 1, 1, 1); 198 gtk_label_set_xalign(GTK_LABEL(label_addr), 0.0); 199 200 /* Third row */ 201 label = gtk_label_new(_("Remarks")); 202 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1); 203 gtk_label_set_xalign(GTK_LABEL(label), 0.0); 204 205 entry_rems = gtk_entry_new(); 206 gtk_widget_set_size_request(entry_rems, 150, -1); 207 gtk_grid_attach(GTK_GRID(table), entry_rems, 1, 2, 1, 1); 208 gtk_widget_set_hexpand(entry_rems, TRUE); 209 gtk_widget_set_halign(entry_rems, GTK_ALIGN_FILL); 210 211 /* Address book/folder tree */ 212 vlbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, VBOX_BORDER); 213 gtk_box_pack_start(GTK_BOX(vbox), vlbox, TRUE, TRUE, 0); 214 gtk_container_set_border_width( GTK_CONTAINER(vlbox), 4); 215 216 tree_win = gtk_scrolled_window_new( NULL, NULL ); 217 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win), 218 GTK_POLICY_AUTOMATIC, 219 GTK_POLICY_AUTOMATIC ); 220 gtk_box_pack_start( GTK_BOX(vlbox), tree_win, TRUE, TRUE, 0 ); 221 222 store = gtk_tree_store_new(N_ADDRADD_COLS, 223 GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); 224 225 tree_folder = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); 226 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), ADDRADD_COL_NAME, GTK_SORT_ASCENDING); 227 g_object_unref(store); 228 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_folder), TRUE); 229 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(tree_folder), FALSE); 230 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree_folder), 231 ADDRADD_COL_NAME); 232 233 /* Column with addressbook/folder icon and name. It has two 234 * renderers, so we create it a bit differently. */ 235 col = gtk_tree_view_column_new(); 236 rdr = gtk_cell_renderer_pixbuf_new(); 237 gtk_cell_renderer_set_padding(rdr, 0, 0); 238 gtk_tree_view_column_pack_start(col, rdr, FALSE); 239 gtk_tree_view_column_set_attributes(col, rdr, 240 "pixbuf", ADDRADD_COL_ICON, NULL); 241 rdr = gtk_cell_renderer_text_new(); 242 gtk_tree_view_column_pack_start(col, rdr, TRUE); 243 gtk_tree_view_column_set_attributes(col, rdr, 244 "markup", ADDRADD_COL_NAME, NULL); 245 gtk_tree_view_column_set_title(col, _("Select Address Book Folder")); 246 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_folder), col); 247 248 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_folder)); 249 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE); 250 251 gtk_container_add( GTK_CONTAINER(tree_win), tree_folder ); 252 253 g_signal_connect(G_OBJECT(tree_folder), "row-activated", 254 G_CALLBACK(addressadd_tree_row_activated), NULL); 255 256 /* Button panel */ 257 gtkut_stock_button_set_create(&hbbox, &cancel_btn, NULL, _("_Cancel"), 258 &ok_btn, NULL, _("_OK"), 259 NULL, NULL, NULL); 260 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); 261 gtk_container_set_border_width( GTK_CONTAINER(hbbox), HSPACING_NARROW ); 262 gtk_widget_grab_default(ok_btn); 263 264 g_signal_connect(G_OBJECT(ok_btn), "clicked", 265 G_CALLBACK(addressadd_ok), NULL); 266 g_signal_connect(G_OBJECT(cancel_btn), "clicked", 267 G_CALLBACK(addressadd_cancel), NULL); 268 269 if (!geometry.min_height) { 270 geometry.min_width = 300; 271 geometry.min_height = 350; 272 } 273 274 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry, 275 GDK_HINT_MIN_SIZE); 276 gtk_window_set_default_size(GTK_WINDOW(window), 277 prefs_common.addressaddwin_width, 278 prefs_common.addressaddwin_height); 279 280 addressadd_dlg.window = window; 281 addressadd_dlg.picture = picture; 282 addressadd_dlg.entry_name = entry_name; 283 addressadd_dlg.label_address = label_addr; 284 addressadd_dlg.entry_remarks = entry_rems; 285 addressadd_dlg.tree_folder = tree_folder; 286 addressadd_dlg.ok_btn = ok_btn; 287 addressadd_dlg.cancel_btn = cancel_btn; 288 289 gtk_widget_show_all( window ); 290 291 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookXpm ); 292 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderXpm ); 293 } 294 295 /* Helper function used by addressadd_tree_clear(). */ 296 static gboolean close_dialog_foreach_func(GtkTreeModel *model, 297 GtkTreePath *path, 298 GtkTreeIter *iter, 299 gpointer user_data) 300 { 301 FolderInfo *fi; 302 303 gtk_tree_model_get(model, iter, ADDRADD_COL_PTR, &fi, -1); 304 if (fi != NULL) { 305 addressadd_free_folderinfo(fi); 306 } 307 gtk_tree_store_set(GTK_TREE_STORE(model), iter, ADDRADD_COL_PTR, NULL, -1); 308 return FALSE; 309 } 310 311 /* Function to remove all rows from the tree view, and free the 312 * FolderInfo pointers in them in pointer column. */ 313 static void addressadd_tree_clear() 314 { 315 GtkWidget *view = addressadd_dlg.tree_folder; 316 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 317 318 gtk_tree_model_foreach(model, close_dialog_foreach_func, NULL); 319 gtk_tree_store_clear(GTK_TREE_STORE(model)); 320 } 321 322 static void addressadd_load_folder( GtkTreeIter *parent_iter, 323 ItemFolder *parentFolder, FolderInfo *fiParent ) 324 { 325 GtkWidget *view = addressadd_dlg.tree_folder; 326 GtkTreeIter iter; 327 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 328 GList *list; 329 ItemFolder *folder; 330 gchar *name; 331 FolderInfo *fi; 332 333 list = parentFolder != NULL? parentFolder->listFolder: NULL; 334 while( list ) { 335 folder = list->data; 336 name = g_strdup( ADDRITEM_NAME(folder) ); 337 fi = addressadd_create_folderinfo( fiParent->book, folder ); 338 339 gtk_tree_store_append(GTK_TREE_STORE(model), &iter, parent_iter); 340 gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 341 ADDRADD_COL_ICON, folderXpm, 342 ADDRADD_COL_NAME, name, 343 ADDRADD_COL_PTR, fi, 344 -1); 345 g_free( name ); 346 347 addressadd_load_folder( parent_iter, folder, fi ); 348 349 list = g_list_next( list ); 350 } 351 } 352 353 static void addressadd_load_data( AddressIndex *addrIndex ) { 354 AddressDataSource *ds; 355 GList *list, *nodeDS; 356 gchar *name; 357 ItemFolder *rootFolder; 358 AddressBookFile *abf; 359 FolderInfo *fi; 360 GtkWidget *view = addressadd_dlg.tree_folder; 361 GtkTreeIter iter; 362 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); 363 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); 364 365 addressadd_tree_clear(); 366 367 list = addrindex_get_interface_list( addrIndex ); 368 while( list ) { 369 AddressInterface *ainterface = list->data; 370 if(ainterface->type == ADDR_IF_BOOK) { 371 nodeDS = ainterface->listSource; 372 while( nodeDS ) { 373 ds = nodeDS->data; 374 name = g_strdup( addrindex_ds_get_name( ds ) ); 375 376 /* Read address book */ 377 if( ! addrindex_ds_get_read_flag( ds ) ) { 378 addrindex_ds_read_data( ds ); 379 } 380 381 /* Add node for address book */ 382 abf = ds->rawDataSource; 383 fi = addressadd_create_folderinfo( abf, NULL ); 384 385 gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL); 386 gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 387 ADDRADD_COL_ICON, bookXpm, 388 ADDRADD_COL_NAME, name, 389 ADDRADD_COL_PTR, fi, 390 -1); 391 g_free( name ); 392 393 rootFolder = addrindex_ds_get_root_folder( ds ); 394 addressadd_load_folder( &iter, rootFolder, fi ); 395 396 nodeDS = g_list_next( nodeDS ); 397 } 398 } 399 list = g_list_next( list ); 400 } 401 402 if (gtk_tree_model_get_iter_first(model, &iter)) 403 gtk_tree_selection_select_iter(sel, &iter); 404 } 405 406 gboolean addressadd_selection( AddressIndex *addrIndex, const gchar *name, 407 const gchar *address, const gchar *remarks, GdkPixbuf *picture ) { 408 gboolean retVal = FALSE; 409 ItemPerson *person = NULL; 410 FolderInfo *fi = NULL; 411 addressadd_cancelled = FALSE; 412 413 if( ! addressadd_dlg.window ) addressadd_create(); 414 415 addressadd_dlg.fiSelected = NULL; 416 addressadd_load_data( addrIndex ); 417 418 gtk_widget_show(addressadd_dlg.window); 419 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg.window), TRUE); 420 gtk_widget_grab_focus(addressadd_dlg.ok_btn); 421 422 manage_window_set_transient(GTK_WINDOW(addressadd_dlg.window)); 423 424 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg.entry_name ), "" ); 425 gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_address ), "" ); 426 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg.entry_remarks ), "" ); 427 if( name ) 428 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg.entry_name ), name ); 429 if( address ) 430 gtk_label_set_text( GTK_LABEL(addressadd_dlg.label_address ), address ); 431 if( remarks ) 432 gtk_entry_set_text( GTK_ENTRY(addressadd_dlg.entry_remarks ), remarks ); 433 if( picture ) { 434 gtk_image_set_from_pixbuf(GTK_IMAGE(addressadd_dlg.picture), picture); 435 gtk_widget_show(GTK_WIDGET(addressadd_dlg.picture)); 436 } else { 437 gtk_widget_hide(GTK_WIDGET(addressadd_dlg.picture)); 438 } 439 gtk_main(); 440 gtk_widget_hide( addressadd_dlg.window ); 441 gtk_window_set_modal(GTK_WINDOW(addressadd_dlg.window), FALSE); 442 if( ! addressadd_cancelled ) { 443 if( addressadd_dlg.fiSelected ) { 444 gchar *returned_name; 445 gchar *returned_remarks; 446 returned_name = gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg.entry_name), 0, -1 ); 447 returned_remarks = gtk_editable_get_chars( GTK_EDITABLE(addressadd_dlg.entry_remarks), 0, -1 ); 448 449 fi = addressadd_dlg.fiSelected; 450 451 person = addrbook_add_contact( fi->book, fi->folder, 452 returned_name, 453 address, 454 returned_remarks); 455 456 if (person != NULL) { 457 person->status = ADD_ENTRY; 458 459 if (picture) { 460 GError *error = NULL; 461 gchar *name = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 462 ADDRITEM_ID(person), ".png", NULL ); 463 gdk_pixbuf_save(picture, name, "png", &error, NULL); 464 if (error) { 465 g_warning("failed to save image: %s", error->message); 466 g_error_free(error); 467 } 468 addritem_person_set_picture( person, ADDRITEM_ID(person) ) ; 469 g_free( name ); 470 } 471 } 472 473 g_free(returned_name); 474 g_free(returned_remarks); 475 if( person ) retVal = TRUE; 476 } 477 } 478 479 addressadd_tree_clear(); 480 481 return retVal; 482 }