1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2012 Match Grun and the Claws Mail team
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 /*
21  * Add address to address book dialog.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #include "claws-features.h"
27 #endif
28 
29 #include "defs.h"
30 
31 #include <glib.h>
32 #include <glib/gi18n.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <gtk/gtk.h>
35 
36 #include "gtkutils.h"
37 #include "stock_pixmap.h"
38 #include "prefs_common.h"
39 #include "addressadd.h"
40 #include "addritem.h"
41 #include "addrbook.h"
42 #include "addrindex.h"
43 #include "manage_window.h"
44 
45 enum {
46 	COL_ICON,
47 	COL_NAME,
48 	COL_PTR,
49 	N_COLS
50 };
51 
52 typedef struct {
53 	AddressBookFile	*book;
54 	ItemFolder	*folder;
55 } FolderInfo;
56 
57 static struct _AddressBookFolderSel_dlg {
58 	GtkWidget *window;
59 	GtkWidget *view_folder;
60 	GtkWidget *ok_btn;
61 	GtkWidget *cancel_btn;
62 	gint status_cid;
63 	FolderInfo *fiSelected;
64 } addressbook_foldersel_dlg;
65 
66 static GdkPixbuf *folderXpm;
67 static GdkPixbuf *bookXpm;
68 
69 static gboolean addressbook_foldersel_cancelled;
70 
addressbook_foldersel_create_folderinfo(AddressBookFile * abf,ItemFolder * folder)71 static FolderInfo *addressbook_foldersel_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
72 {
73 	FolderInfo *fi = g_new0( FolderInfo, 1 );
74 	fi->book   = abf;
75 	fi->folder = folder;
76 	return fi;
77 }
78 
addressbook_foldersel_free_folderinfo(FolderInfo * fi)79 static void addressbook_foldersel_free_folderinfo( FolderInfo *fi ) {
80 	fi->book   = NULL;
81 	fi->folder = NULL;
82 	g_free( fi );
83 }
84 
addressbook_foldersel_delete_event(GtkWidget * widget,GdkEventAny * event,gboolean * cancelled)85 static gint addressbook_foldersel_delete_event( GtkWidget *widget, GdkEventAny *event, gboolean *cancelled )
86 {
87 	addressbook_foldersel_cancelled = TRUE;
88 	gtk_main_quit();
89 	return TRUE;
90 }
91 
addressbook_foldersel_key_pressed(GtkWidget * widget,GdkEventKey * event,gboolean * cancelled)92 static gboolean addressbook_foldersel_key_pressed( GtkWidget *widget, GdkEventKey *event, gboolean *cancelled )
93 {
94 	if ( event && event->keyval == GDK_KEY_Escape ) {
95 		addressbook_foldersel_cancelled = TRUE;
96 		gtk_main_quit();
97 	}
98 	return FALSE;
99 }
100 
set_selected_ptr()101 static void set_selected_ptr()
102 {
103 	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
104 
105 	addressbook_foldersel_dlg.fiSelected =
106 		gtkut_tree_view_get_selected_pointer(GTK_TREE_VIEW(view), COL_PTR,
107 				NULL, NULL, NULL);
108 }
109 
addressbook_foldersel_ok(GtkWidget * widget,gboolean * cancelled)110 static void addressbook_foldersel_ok( GtkWidget *widget, gboolean *cancelled )
111 {
112 	set_selected_ptr();
113 	addressbook_foldersel_cancelled = FALSE;
114 	gtk_main_quit();
115 }
116 
addressbook_foldersel_cancel(GtkWidget * widget,gboolean * cancelled)117 static void addressbook_foldersel_cancel( GtkWidget *widget, gboolean *cancelled )
118 {
119 	set_selected_ptr();
120 	addressbook_foldersel_cancelled = TRUE;
121 	gtk_main_quit();
122 }
123 
addressbook_foldersel_row_activated(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer user_data)124 static void addressbook_foldersel_row_activated(GtkTreeView *view,
125 		GtkTreePath *path, GtkTreeViewColumn *col,
126 		gpointer user_data)
127 {
128 	addressbook_foldersel_ok(NULL, NULL);
129 }
130 
addressbook_foldersel_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)131 static void addressbook_foldersel_size_allocate_cb(GtkWidget *widget,
132 					 GtkAllocation *allocation)
133 {
134 	cm_return_if_fail(allocation != NULL);
135 
136 	prefs_common.addressbook_folderselwin_width = allocation->width;
137 	prefs_common.addressbook_folderselwin_height = allocation->height;
138 }
139 
addressbook_foldersel_create(void)140 static void addressbook_foldersel_create( void )
141 {
142 	GtkWidget *window;
143 	GtkWidget *vbox;
144 	GtkWidget *view;
145 	GtkWidget *vlbox;
146 	GtkWidget *tree_win;
147 	GtkWidget *hbbox;
148 	GtkWidget *ok_btn;
149 	GtkWidget *cancel_btn;
150 	static GdkGeometry geometry;
151 	GtkTreeStore *store;
152 	GtkTreeSelection *sel;
153 	GtkCellRenderer *rdr;
154 	GtkTreeViewColumn *col;
155 
156 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook_foldersel" );
157 	gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
158 	gtk_window_set_title( GTK_WINDOW(window), _("Select Address Book Folder") );
159 	gtk_window_set_position( GTK_WINDOW(window), GTK_WIN_POS_MOUSE );
160 	gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
161 	g_signal_connect( G_OBJECT(window), "delete_event",
162 			  G_CALLBACK(addressbook_foldersel_delete_event), NULL );
163 	g_signal_connect( G_OBJECT(window), "key_press_event",
164 			  G_CALLBACK(addressbook_foldersel_key_pressed), NULL );
165 	g_signal_connect(G_OBJECT(window), "size_allocate",
166 			 G_CALLBACK(addressbook_foldersel_size_allocate_cb), NULL);
167 
168 	vbox = gtk_vbox_new(FALSE, 8);
169 	gtk_container_add(GTK_CONTAINER(window), vbox);
170 	gtk_container_set_border_width( GTK_CONTAINER(vbox), 8 );
171 
172 	/* Address book/folder tree */
173 	vlbox = gtk_vbox_new(FALSE, 8);
174 	gtk_box_pack_start(GTK_BOX(vbox), vlbox, TRUE, TRUE, 0);
175 	gtk_container_set_border_width( GTK_CONTAINER(vlbox), 8 );
176 
177 	tree_win = gtk_scrolled_window_new( NULL, NULL );
178 	gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win),
179 				        GTK_POLICY_AUTOMATIC,
180 				        GTK_POLICY_AUTOMATIC );
181 	gtk_box_pack_start( GTK_BOX(vlbox), tree_win, TRUE, TRUE, 0 );
182 
183 	store = gtk_tree_store_new(N_COLS,
184 			GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
185 
186 	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
187 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), COL_NAME, GTK_SORT_ASCENDING);
188 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), prefs_common.use_stripes_everywhere);
189 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
190 	gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(view), FALSE);
191 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(view), COL_NAME);
192 
193 	col = gtk_tree_view_column_new();
194 	rdr = gtk_cell_renderer_pixbuf_new();
195 	gtk_cell_renderer_set_padding(rdr, 0, 0);
196 	gtk_tree_view_column_pack_start(col, rdr, FALSE);
197 	gtk_tree_view_column_set_attributes(col, rdr,
198 			"pixbuf", COL_ICON, NULL);
199 	rdr = gtk_cell_renderer_text_new();
200 	gtk_tree_view_column_pack_start(col, rdr, TRUE);
201 	gtk_tree_view_column_set_attributes(col, rdr,
202 			"markup", COL_NAME, NULL);
203 	gtk_tree_view_column_set_title(col, _("Address Book"));
204 	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
205 
206 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
207 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
208 
209 	gtk_container_add( GTK_CONTAINER(tree_win), view );
210 
211 	/* Button panel */
212 	gtkut_stock_button_set_create( &hbbox, &cancel_btn, GTK_STOCK_CANCEL,
213 				      &ok_btn, GTK_STOCK_OK,
214 				      NULL, NULL );
215 	gtk_box_pack_end( GTK_BOX(vbox), hbbox, FALSE, FALSE, 0 );
216 	gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
217 	gtk_widget_grab_default( ok_btn );
218 
219 	g_signal_connect( G_OBJECT(view), "row-activated",
220 			G_CALLBACK(addressbook_foldersel_row_activated), NULL);
221 	g_signal_connect( G_OBJECT(ok_btn), "clicked",
222 			 G_CALLBACK(addressbook_foldersel_ok), NULL );
223 	g_signal_connect( G_OBJECT(cancel_btn), "clicked",
224 			 G_CALLBACK(addressbook_foldersel_cancel), NULL );
225 
226 	if ( !geometry.min_height ) {
227 		geometry.min_width = 300;
228 		geometry.min_height = 350;
229 	}
230 
231 	gtk_window_set_geometry_hints( GTK_WINDOW(window), NULL, &geometry,
232 				      GDK_HINT_MIN_SIZE );
233 	gtk_widget_set_size_request( window, prefs_common.addressbook_folderselwin_width,
234 				    prefs_common.addressbook_folderselwin_height );
235 
236 	gtk_widget_show_all( vbox );
237 
238 	addressbook_foldersel_dlg.window      = window;
239 	addressbook_foldersel_dlg.view_folder = view;
240 	addressbook_foldersel_dlg.ok_btn      = ok_btn;
241 	addressbook_foldersel_dlg.cancel_btn  = cancel_btn;
242 
243 	gtk_widget_show_all( window );
244 
245 	stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookXpm);
246 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderXpm);
247 }
248 
tree_clear_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)249 static gboolean tree_clear_foreach_func(GtkTreeModel *model,
250 		GtkTreePath *path, GtkTreeIter *iter,
251 		gpointer user_data)
252 {
253 	FolderInfo *fi;
254 
255 	gtk_tree_model_get(model, iter, COL_PTR, &fi, -1);
256 	if (fi != NULL) {
257 		addressbook_foldersel_free_folderinfo(fi);
258 	}
259 	gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_PTR, NULL, -1);
260 	return FALSE;
261 }
262 
addressbook_foldersel_tree_clear()263 static void addressbook_foldersel_tree_clear()
264 {
265 	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
266 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
267 
268 	gtk_tree_model_foreach(model, tree_clear_foreach_func, NULL);
269 	gtk_tree_store_clear(GTK_TREE_STORE(model));
270 }
271 
addressbook_foldersel_load_folder(GtkTreeIter * parent_iter,ItemFolder * parentFolder,FolderInfo * fiParent)272 static void addressbook_foldersel_load_folder( GtkTreeIter *parent_iter,
273 		ItemFolder *parentFolder, FolderInfo *fiParent)
274 {
275 	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
276 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
277 	GtkTreeIter iter;
278 	GList *list;
279 	ItemFolder *folder;
280 	gchar *name;
281 	FolderInfo *fi;
282 
283 	list = parentFolder->listFolder;
284 	while ( list ) {
285 		folder = list->data;
286 		name = g_strdup( ADDRITEM_NAME(folder) );
287 
288 		fi = addressbook_foldersel_create_folderinfo( fiParent->book, folder );
289 
290 		debug_print("adding folder '%s'\n", name);
291 		gtk_tree_store_append(GTK_TREE_STORE(model), &iter, parent_iter);
292 		gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
293 				COL_ICON, folderXpm,
294 				COL_NAME, name,
295 				COL_PTR, fi,
296 				-1);
297 		g_free(name);
298 
299 		addressbook_foldersel_load_folder( parent_iter, folder, fi );
300 		list = g_list_next( list );
301 	}
302 }
303 
addressbook_foldersel_load_data(AddressIndex * addrIndex)304 static void addressbook_foldersel_load_data( AddressIndex *addrIndex )
305 {
306 	AddressDataSource *ds;
307 	GList *list, *nodeDS;
308 	gchar *name;
309 	ItemFolder *rootFolder;
310 	AddressBookFile *abf;
311 	FolderInfo *fi;
312 	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
313 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
314 	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
315 	GtkTreeIter iter;
316 
317 	addressbook_foldersel_tree_clear();
318 
319 	list = addrindex_get_interface_list( addrIndex );
320 	while ( list ) {
321 		AddressInterface *interface = list->data;
322 		if ( interface->type == ADDR_IF_BOOK ) {
323 			nodeDS = interface->listSource;
324 			while ( nodeDS ) {
325 				ds = nodeDS->data;
326 				name = g_strdup( addrindex_ds_get_name( ds ) );
327 
328 				/* Read address book */
329 				if( ! addrindex_ds_get_read_flag( ds ) ) {
330 					addrindex_ds_read_data( ds );
331 				}
332 
333 				/* Add node for address book */
334 				abf = ds->rawDataSource;
335 				fi = addressbook_foldersel_create_folderinfo( abf, NULL );
336 
337 				debug_print("adding AB '%s'\n", name);
338 				gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
339 				gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
340 						COL_ICON, bookXpm,
341 						COL_NAME, name,
342 						COL_PTR, fi,
343 						-1);
344 				g_free(name);
345 
346 				rootFolder = addrindex_ds_get_root_folder( ds );
347 				addressbook_foldersel_load_folder( &iter, rootFolder, fi );
348 
349 				nodeDS = g_list_next( nodeDS );
350 			}
351 		}
352 		list = g_list_next( list );
353 	}
354 
355 	if (gtk_tree_model_get_iter_first(model, &iter))
356 		gtk_tree_selection_select_iter(sel, &iter);
357 }
358 
addressbook_foldersel_selection(AddressIndex * addrIndex,AddressBookFile ** book,ItemFolder ** folder,const gchar * path)359 gboolean addressbook_foldersel_selection( AddressIndex *addrIndex,
360 					AddressBookFile **book, ItemFolder **folder,
361 					const gchar* path)
362 {
363 	gboolean retVal = FALSE;
364 	addressbook_foldersel_cancelled = FALSE;
365 
366 	if ( ! addressbook_foldersel_dlg.window )
367 		addressbook_foldersel_create();
368 	gtk_widget_grab_focus(addressbook_foldersel_dlg.ok_btn);
369 	gtk_widget_show(addressbook_foldersel_dlg.window);
370 	manage_window_set_transient(GTK_WINDOW(addressbook_foldersel_dlg.window));
371 	gtk_window_set_modal(GTK_WINDOW(addressbook_foldersel_dlg.window), TRUE);
372 
373 	addressbook_foldersel_dlg.fiSelected = NULL;
374 
375 	addressbook_foldersel_load_data( addrIndex );
376 
377 	gtk_widget_show(addressbook_foldersel_dlg.window);
378 
379 	gtk_main();
380 	gtk_widget_hide( addressbook_foldersel_dlg.window );
381 	gtk_window_set_modal(GTK_WINDOW(addressbook_foldersel_dlg.window), FALSE);
382 	if ( ! addressbook_foldersel_cancelled ) {
383 
384 		*book = NULL;
385 		*folder = NULL;
386 
387 		if ( addressbook_foldersel_dlg.fiSelected ) {
388 			*book = addressbook_foldersel_dlg.fiSelected->book;
389 			*folder = addressbook_foldersel_dlg.fiSelected->folder;
390 			retVal = TRUE;
391 		}
392 	}
393 
394 	addressbook_foldersel_tree_clear();
395 
396 	return retVal;
397 }
398 
399 /*
400 * End of Source.
401 */
402