talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

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 }