1 /*  Copyright (C) 2001-2004  Kenichi Suto
2  *
3  *  This program is free software; you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 */
17 
18 #include "defs.h"
19 #include "global.h"
20 
21 #include "jcode.h"
22 #include "grep.h"
23 #include "pixmap.h"
24 #include "pref_io.h"
25 #include "dirtree.h"
26 
27 static GtkTreeStore *directory_store=NULL;
28 GtkWidget *directory_view=NULL;
29 
30 GList *active_dir_list=NULL;
31 
32 static GdkPixbuf *pixbuf_file;
33 static GdkPixbuf *pixbuf_folder_closed;
34 static GdkPixbuf *pixbuf_folder_open;
35 
unicode_to_fs(gchar * from)36 gchar *unicode_to_fs(gchar *from)
37 {
38 	gchar *to;
39 
40 	to = iconv_convert("utf-8", fs_codeset, from);
41 
42 	return(to);
43 }
44 
fs_to_unicode(gchar * from)45 gchar *fs_to_unicode(gchar *from)
46 {
47 	gchar *to;
48 
49 	to = iconv_convert(fs_codeset, "utf-8", from);
50 
51 	return(to);
52 }
53 
native_to_generic(gchar * from)54 gchar *native_to_generic(gchar *from)
55 {
56 #ifdef __WIN32__
57 	gchar buff[512];
58 	gint i, j;
59 #endif
60 	gchar *p;
61 	LOG(LOG_DEBUG, "IN : native_to_generic(%s)", from);
62 
63 #ifdef __WIN32__
64 //	if((from[1] != ':') || (from[2] != '\\')){
65 	if(from[1] != ':'){
66 		LOG(LOG_DEBUG, "OUT : native_to_generic() = NULL");
67 		return(NULL);
68 	}
69 
70 	buff[0] = '/';
71 	buff[1] = from[0];
72 
73 	i = j = 2;
74 	while(1){
75 		if(from[i] == '\\')
76 			buff[j] = '/';
77 		else
78 			buff[j] = from[i];
79 		if(from[i] == '\0')
80 			break;
81 		i ++;
82 		j ++;
83 	}
84 
85 	p = fs_to_unicode(buff);
86 
87 	LOG(LOG_DEBUG, "OUT : native_to_generic() = %s", p);
88 	return(p);
89 #else
90 	if(from[0] != '/') {
91 		LOG(LOG_DEBUG, "OUT : native_to_generic() = NULL");
92 		return(NULL);
93 	}
94 
95 	p = fs_to_unicode(from);
96 
97 	LOG(LOG_DEBUG, "OUT : native_to_generic() = %s", p);
98 	return(p);
99 #endif
100 }
101 
generic_to_native(gchar * from)102 gchar *generic_to_native(gchar *from)
103 {
104 #ifdef __WIN32__
105 	gchar buff[512];
106 	gint i, j;
107 #endif
108 	gchar *p;
109 
110 	LOG(LOG_DEBUG, "IN : generic_to_native(%s)", from);
111 
112 	if(from[0] != '/') {
113 		LOG(LOG_DEBUG, "OUT : generic_to_native() = NULL");
114 		return(NULL);
115 	}
116 
117 #ifdef __WIN32__
118 
119 	p = unicode_to_fs(from);
120 	if(p == NULL) {
121 		LOG(LOG_DEBUG, "OUT : generic_to_native() = NULL");
122 		return(NULL);
123 	}
124 
125 	buff[0] = p[1];
126 	buff[1] = ':';
127 
128 	i = j = 2;
129 	while(1){
130 		if(p[i] == '/')
131 			buff[j] = '\\';
132 		else
133 			buff[j] = p[i];
134 		if(p[i] == '\0')
135 			break;
136 		i ++;
137 		j ++;
138 	}
139 
140 	if(strlen(buff) == 2)
141 		strcat(buff, "\\");
142 
143 	g_free(p);
144 
145 	LOG(LOG_DEBUG, "OUT : generic_to_native() = %s", buff);
146 	return(strdup(buff));
147 #else
148 	p = unicode_to_fs(from);
149 
150 	LOG(LOG_DEBUG, "OUT : generic_to_native() = %s", p);
151 	return(p);
152 #endif
153 }
154 
155 
156 
157 static gchar *compose_full_path(GtkTreePath *path);
158 
159 enum
160 {
161 	DIR_ACTIVATABLE_COLUMN,
162 	DIR_ACTIVE_COLUMN,
163 	DIR_PIXBUF_COLUMN,
164 	DIR_PIXBUF_CLOSED_COLUMN,
165 	DIR_PIXBUF_OPEN_COLUMN,
166 	DIR_NAME_COLUMN,
167 	DIR_N_COLUMNS
168 };
169 
compare_func(gconstpointer a,gconstpointer b)170 static gint compare_func(gconstpointer a, gconstpointer b){
171 	return(strcmp(a,b));
172 }
173 
reverse_compare_func(gconstpointer a,gconstpointer b)174 static gint reverse_compare_func(gconstpointer a, gconstpointer b){
175 	gint r;
176 
177 	r = strcmp(a,b);
178 	if(r < 0)
179 		return(1);
180 	else if(r > 0)
181 		return(-1);
182 	else
183 		return(0);
184 }
185 
186 
button_press_event(GtkWidget * widget,GdkEventButton * event)187 static gint button_press_event(GtkWidget *widget, GdkEventButton *event)
188 {
189 	GtkTreeIter iter;
190 	GtkTreeSelection *selection;
191 	GtkTreePath *path;
192 
193 	LOG(LOG_DEBUG, "IN : button_press_event()");
194 	if ((event->type == GDK_BUTTON_PRESS) &&
195 	    (event->button == 1)){
196 
197 		// invert characters on mouse
198 		if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(directory_view),
199 					      (gint)(event->x),
200 					      (gint)(event->y),
201 					      &path,
202 						 NULL, NULL, NULL) == FALSE){
203 			return(FALSE);
204 		}
205 
206 		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(directory_view));
207 		gtk_tree_selection_select_path(selection, path);
208 
209 		if(event->state & GDK_CONTROL_MASK){
210 			gboolean active;
211 			gchar *dirname;
212 			GList *l;
213 
214 			dirname = compose_full_path(path);
215 
216 			gtk_tree_model_get_iter(GTK_TREE_MODEL(directory_store), &iter, path);
217 			gtk_tree_model_get(GTK_TREE_MODEL(directory_store), &iter, DIR_ACTIVE_COLUMN, &active, -1);
218 			if(active){
219 				gtk_tree_store_set(directory_store,
220 						   &iter,
221 						   DIR_ACTIVE_COLUMN, FALSE,
222 						   -1);
223 
224 				l = g_list_first(active_dir_list);
225 				while(l){
226 					if(strcmp(l->data, dirname) == 0){
227 						active_dir_list = g_list_remove(active_dir_list, l->data);
228 						g_free(l->data);
229 						g_free(dirname);
230 						break;
231 					}
232 					l = g_list_next(l);
233 				}
234 			} else {
235 				gtk_tree_store_set(directory_store,
236 						   &iter,
237 						   DIR_ACTIVE_COLUMN, TRUE,
238 						   -1);
239 
240 				active_dir_list = g_list_append(active_dir_list, dirname);
241 
242 			}
243 		}
244 
245 		return(TRUE);
246 	}
247 
248 	if ((event->type == GDK_2BUTTON_PRESS) &&
249 	    (event->button == 1)){
250 		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(directory_view));
251 		if (gtk_tree_selection_get_selected(selection, NULL, &iter) == FALSE) {
252 			return(TRUE);
253 		}
254 
255 		path = gtk_tree_model_get_path(GTK_TREE_MODEL(directory_store),
256 					       &iter);
257 
258 		if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(directory_store), &iter) == TRUE){
259 			if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(directory_view), path)){
260 				gtk_tree_view_collapse_row(GTK_TREE_VIEW(directory_view), path);
261 			} else {
262 				gtk_tree_view_expand_row(GTK_TREE_VIEW(directory_view), path, FALSE);
263 			}
264 		} else {
265 			RESULT result;
266 			gchar *fullname;
267 			gchar *tmpp;
268 
269 			tmpp = compose_full_path(path);
270 			fullname = generic_to_native(tmpp);
271 			if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR) == TRUE){
272 				result.heading = NULL;
273 				result.word = NULL;
274 				result.type = RESULT_TYPE_GREP;
275 				result.data.grep.filename = tmpp;
276 				result.data.grep.page = 1;
277 				result.data.grep.line = 1;
278 				result.data.grep.offset = 0;
279 
280 				open_file(&result);
281 			}
282 
283 			g_free(fullname);
284 			g_free(tmpp);
285 
286 		}
287 		gtk_tree_path_free(path);
288 		return(TRUE);
289 	}
290 
291 
292 	LOG(LOG_DEBUG, "OUT : button_press_event() = FALSE");
293 	return(FALSE);
294 }
295 
296 
compose_full_path(GtkTreePath * path)297 static gchar *compose_full_path(GtkTreePath *path)
298 {
299 	gchar *dirname=NULL;
300 	gchar buff[512];
301 	GtkTreePath *tmp_path;
302 	GtkTreeIter parent;
303 	gchar *name;
304 
305 	LOG(LOG_DEBUG, "IN : compose_full_path()");
306 
307 
308 	// Compose full path by going up the path.
309 
310 	tmp_path = gtk_tree_path_copy(path);
311 	while(1)
312 	{
313 		gtk_tree_model_get_iter(GTK_TREE_MODEL(directory_store), &parent, tmp_path);
314 		gtk_tree_model_get(GTK_TREE_MODEL(directory_store), &parent, DIR_NAME_COLUMN, &name, -1);
315 
316 		if((name[1] == ':') && (name[2] == '\\')){
317 			buff[0] = name[0];
318 			buff[1] = '\0';
319 		} else
320 			strcpy(buff, name);
321 
322 		if(dirname){
323 			if(buff[strlen(buff)-1] == '/') {
324 				strcat(buff, dirname);
325 			} else {
326 				strcat(buff, "/");
327 				strcat(buff, dirname);
328 			}
329 			g_free(dirname);
330 		}
331 		dirname = strdup(buff);
332 
333 		g_free(name);
334 		gtk_tree_path_up(tmp_path);
335 		if(gtk_tree_path_get_depth(tmp_path) <= 0)
336 			break;
337        }
338 	gtk_tree_path_free(tmp_path);
339 
340 	sprintf(buff, "/%s", dirname);
341 	g_free(dirname);
342 	dirname = strdup(buff);
343 
344 	LOG(LOG_DEBUG, "OUT : compose_full_path() = %s", dirname);
345 
346 	return(dirname);
347 }
348 
row_collapsed(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)349 static void row_collapsed(GtkTreeView *treeview,
350 			GtkTreeIter *iter,
351 			GtkTreePath *path,
352 			gpointer user_data)
353 {
354 /*
355 	// Closed folder icon
356 	gtk_tree_store_set(directory_store,
357 			   iter,
358 			   DIR_PIXBUF_COLUMN, pixbuf_folder_closed,
359 			   DIR_PIXBUF_CLOSED_COLUMN, pixbuf_folder_closed,
360 			   DIR_PIXBUF_OPEN_COLUMN, pixbuf_folder_open,
361 			   -1);
362 */
363 }
364 
row_expanded(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)365 static void row_expanded(GtkTreeView *treeview,
366 			GtkTreeIter *iter,
367 			GtkTreePath *path,
368 			gpointer user_data)
369 {
370 	gchar *dirname=NULL;
371 	gchar *tmpp;
372 	gchar *name;
373 	gchar *fullpath=NULL;
374 	GDir *dir;
375 	GtkTreeIter child;
376 	GtkTreeIter grand_child;
377 	GList *dir_list = NULL;
378 	GList *file_list = NULL;
379 	GList *l;
380 	gint count=0;
381 
382 
383 	LOG(LOG_DEBUG, "IN : row_expanded()");
384 
385 	tmpp = compose_full_path(path);
386 	dirname = generic_to_native(tmpp);
387 	g_free(tmpp);
388 
389 	if((dir = g_dir_open(dirname, 0, NULL)) == NULL){
390 		LOG(LOG_CRITICAL, "Failed to open directory %s", dirname);
391 		return;
392 	}
393 
394 	// Create entry list in the directory.
395 	while((name = (gchar *)g_dir_read_name(dir)) != NULL){
396 		fullpath = g_strdup_printf("%s%s%s", dirname, DIR_DELIMITER, name);
397 		if(g_file_test(fullpath, G_FILE_TEST_IS_REGULAR) == TRUE){
398 			tmpp = iconv_convert(fs_codeset, "utf-8", name);
399 			if((tmpp == NULL) || (strlen(tmpp) == 0)){
400 				LOG(LOG_CRITICAL, "Failed to convert filename from %s", fs_codeset);
401 				continue;
402 			}
403 			file_list = g_list_append(file_list, tmpp);
404 		} else if((g_file_test(fullpath, G_FILE_TEST_IS_DIR) == TRUE)){
405 			tmpp = iconv_convert(fs_codeset, "utf-8", name);
406 			if((tmpp == NULL) || (strlen(tmpp) == 0)){
407 				LOG(LOG_CRITICAL, "Failed to convert filename from %s", fs_codeset);
408 				continue;
409 			}
410 			dir_list = g_list_append(dir_list, tmpp);
411 		}
412 	}
413 	g_dir_close(dir);
414 	g_free(dirname);
415 
416 	// Since insertion is done by "prepend", reverse sort.
417 	g_list_sort(dir_list, reverse_compare_func);
418 	g_list_sort(file_list, reverse_compare_func);
419 
420 
421 	l = g_list_first(file_list);
422 	while(l){
423 		gchar *name;
424 		name = l->data;
425 
426 		// Files and directories starting by dot will not be shown
427 		if((name[0] == '.') && bsuppress_hidden_files){
428 			g_free(l->data);
429 			l = g_list_next(l);
430 			continue;
431 		}
432 
433 		gtk_tree_store_prepend(directory_store, &child, iter);
434 		gtk_tree_store_set(directory_store,
435 				   &child,
436 				   DIR_NAME_COLUMN, l->data,
437 				   DIR_PIXBUF_COLUMN, pixbuf_file,
438 				   DIR_PIXBUF_CLOSED_COLUMN, pixbuf_folder_closed,
439 				   DIR_PIXBUF_OPEN_COLUMN, pixbuf_folder_open,
440 				   DIR_ACTIVATABLE_COLUMN, TRUE,
441 				   DIR_ACTIVE_COLUMN, FALSE,
442 				   -1);
443 		g_free(l->data);
444 		l = g_list_next(l);
445 		count ++;
446 	}
447 
448 	l = g_list_first(dir_list);
449 	while(l){
450 		gchar *name;
451 		name = l->data;
452 
453 		// Files and directories starting by dot will not be shown
454 		if((name[0] == '.') && bsuppress_hidden_files){
455 			g_free(l->data);
456 			l = g_list_next(l);
457 			continue;
458 		}
459 		gtk_tree_store_prepend(directory_store, &child, iter);
460 		gtk_tree_store_set(directory_store,
461 				   &child,
462 				   DIR_NAME_COLUMN, l->data,
463 				   DIR_PIXBUF_COLUMN, pixbuf_folder_open,
464 				   DIR_PIXBUF_CLOSED_COLUMN, pixbuf_folder_closed,
465 				   DIR_PIXBUF_OPEN_COLUMN, pixbuf_folder_open,
466 				   DIR_ACTIVATABLE_COLUMN, TRUE,
467 				   DIR_ACTIVE_COLUMN, FALSE,
468 				   -1);
469 
470 		// Put dummy in order to show triangle mark.
471 		gtk_tree_store_append(directory_store, &grand_child, &child);
472 		gtk_tree_store_set(directory_store,
473 				   &grand_child,
474 				   DIR_NAME_COLUMN, "DUMMY",
475 				   DIR_ACTIVATABLE_COLUMN, TRUE,
476 				   DIR_ACTIVE_COLUMN, FALSE,
477 				   -1);
478 
479 		g_free(l->data);
480 		l = g_list_next(l);
481 		count++;
482 	}
483 
484 	g_list_free(dir_list);
485 	g_list_free(file_list);
486 
487 
488 	// Because insertion is done by "prepend", remove the rest
489 	while(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(directory_store),
490 					    &child,
491 					    iter,
492 					    count)){
493 		gtk_tree_store_remove(GTK_TREE_STORE(directory_store),
494 				      &child);
495 
496 	}
497 
498 /*
499 	// Closed folder icon
500 	gtk_tree_store_set(directory_store,
501 			   iter,
502 			   DIR_PIXBUF_COLUMN, pixbuf_folder_open,
503 			   -1);
504 
505 */
506 	LOG(LOG_DEBUG, "OUT : row_expanded()");
507 
508 	return;
509 }
510 
item_toggled(GtkCellRendererToggle * cell,gchar * path_str,gpointer data)511 static void item_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
512 {
513 	GtkTreeModel *model = (GtkTreeModel *)directory_store;
514 	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
515 	GtkTreeIter iter;
516 	gboolean toggle_item;
517 
518 	gchar *dirname;
519 	GList *l;
520 
521 	LOG(LOG_DEBUG, "IN : item_toggled()");
522 
523 	gtk_tree_model_get_iter (model, &iter, path);
524 	gtk_tree_model_get (model, &iter, DIR_ACTIVE_COLUMN, &toggle_item, -1);
525 
526 	toggle_item ^= 1;
527 
528 	gtk_tree_store_set (GTK_TREE_STORE (directory_store), &iter, DIR_ACTIVE_COLUMN,
529 			    toggle_item, -1);
530 
531 	dirname = compose_full_path(path);
532 
533 	if(toggle_item)
534 		active_dir_list = g_list_append(active_dir_list, dirname);
535 	else {
536 		l = g_list_first(active_dir_list);
537 		while(l){
538 			if(strcmp(l->data, dirname) == 0){
539 				active_dir_list = g_list_remove(active_dir_list, l->data);
540 				g_free(l->data);
541 				g_free(dirname);
542 				break;
543 			}
544 			l = g_list_next(l);
545 		}
546 	}
547 
548 	gtk_tree_path_free (path);
549 
550 	save_dirlist();
551 
552 	LOG(LOG_DEBUG, "OUT : item_toggled()");
553 }
554 
show_directory()555 static void show_directory()
556 {
557 	GtkTreeIter parent;
558 	GtkTreeIter child;
559 
560 #ifdef __WIN32__
561 	gchar *p;
562 	gchar buff[128];
563 	char tmp[128];
564 
565 	LOG(LOG_DEBUG, "IN : show_directory()");
566 
567 	GetLogicalDriveStrings(sizeof(buff), buff);
568 
569 	p = buff;
570 	while(*p != '\0')
571 	{
572 		if((tolower(p[0]) != 'a') && (tolower(p[0]) != 'b'))
573 		{
574 			g_snprintf(tmp, sizeof(tmp), "%c:\\", toupper(p[0]));
575 			gtk_tree_store_append(directory_store, &parent, NULL);
576 			gtk_tree_store_set(directory_store,
577 					   &parent,
578 					   DIR_NAME_COLUMN, tmp,
579 					   DIR_PIXBUF_COLUMN, pixbuf_file,
580 					   DIR_PIXBUF_CLOSED_COLUMN, pixbuf_folder_closed,
581 					   DIR_PIXBUF_OPEN_COLUMN, pixbuf_folder_open,
582 					   DIR_ACTIVATABLE_COLUMN, TRUE,
583 					   DIR_ACTIVE_COLUMN, FALSE,
584 					   -1);
585 			// Put dummy in order to show triangle mark.
586 			gtk_tree_store_append(directory_store, &child, &parent);
587 			gtk_tree_store_set(directory_store,
588 					   &child,
589 					   DIR_NAME_COLUMN, "DUMMY",
590 					   -1);
591 		}
592 		p += (strlen(p) + 1);
593 	}
594 #else
595 	GDir *dir;
596 	GList *dir_list=NULL;
597 	GList *file_list=NULL;
598 	GList *l;
599 	gchar fullpath[512];
600 	const gchar *name;
601 
602 	LOG(LOG_DEBUG, "IN : show_directory()");
603 
604 	if((dir = g_dir_open("/", 0, NULL)) == NULL){
605 		LOG(LOG_CRITICAL, "Failed to open directory /");
606 		return;
607 	}
608 
609 	while((name = g_dir_read_name(dir)) != NULL){
610 		sprintf(fullpath,"/%s",name);
611 		if(g_file_test(fullpath, G_FILE_TEST_IS_REGULAR) == TRUE){
612 			file_list = g_list_append(file_list, fs_to_unicode((gchar *)name));
613 
614 		} else if(g_file_test(fullpath, G_FILE_TEST_IS_DIR) == TRUE){
615 			dir_list = g_list_append(dir_list, fs_to_unicode((gchar *)name));				}
616 	}
617 	g_dir_close(dir);
618 
619 	g_list_sort(dir_list, compare_func);
620 	g_list_sort(file_list, compare_func);
621 
622 	l = g_list_first(dir_list);
623 	while(l){
624 		gtk_tree_store_append(directory_store, &parent, NULL);
625 		gtk_tree_store_set(directory_store,
626 				   &parent,
627 				   DIR_NAME_COLUMN, l->data,
628 				   DIR_PIXBUF_COLUMN, pixbuf_folder_open,
629 				   DIR_PIXBUF_CLOSED_COLUMN, pixbuf_folder_closed,
630 				   DIR_PIXBUF_OPEN_COLUMN, pixbuf_folder_open,
631 				   DIR_ACTIVATABLE_COLUMN, TRUE,
632 				   DIR_ACTIVE_COLUMN, FALSE,
633 				   -1);
634 
635 		// Put dummy in order to show triangle mark.
636 		gtk_tree_store_append(directory_store, &child, &parent);
637 		gtk_tree_store_set(directory_store,
638 				   &child,
639 				   DIR_NAME_COLUMN, "DUMMY",
640 				   -1);
641 		g_free(l->data);
642 		l = g_list_next(l);
643 	}
644 
645 	l = g_list_first(file_list);
646 	while(l){
647 		gtk_tree_store_append(directory_store, &parent, NULL);
648 		gtk_tree_store_set(directory_store,
649 				   &parent,
650 				   DIR_NAME_COLUMN, l->data,
651 				   DIR_PIXBUF_COLUMN, pixbuf_file,
652 				   DIR_PIXBUF_CLOSED_COLUMN, pixbuf_folder_closed,
653 				   DIR_PIXBUF_OPEN_COLUMN, pixbuf_folder_open,
654 				   DIR_ACTIVATABLE_COLUMN, TRUE,
655 				   DIR_ACTIVE_COLUMN, FALSE,
656 				   -1);
657 		g_free(l->data);
658 		l = g_list_next(l);
659 	}
660 
661 
662 	g_list_free(dir_list);
663 	g_list_free(file_list);
664 #endif
665 
666 	LOG(LOG_DEBUG, "OUT : show_directory()");
667 }
668 
expand_to_path(gchar * name)669 static gboolean expand_to_path(gchar *name)
670 {
671 	gchar *p;
672 	gint i=0;
673 	GtkTreeIter iter;
674 	GtkTreeIter *parent=NULL;
675 	GtkTreePath *path;
676 
677 	LOG(LOG_DEBUG, "IN : expand_to_path(%s)", name);
678 
679 	// Expand to "name", then check "name"
680 	p = name;
681 	for(i=0; ; i++){
682 		gchar *tmp=NULL;
683 
684 		if((name[i] != '/') && (name[i] != '\0')){
685 			continue;
686 		}
687 
688 		if(&name[i] == p){
689 #ifdef __WIN32__
690 			tmp = malloc(4);
691 			tmp[0] = name[i+1];
692 			tmp[1] = ':';
693 			tmp[2] = '\\';
694 			tmp[3] = '\0';
695 			i+=2;
696 			p += 3;
697 #else
698 			// UNIX root
699 			p ++;
700 			continue;
701 #endif
702 		} else if ((i > 1) && (name[i-1] == ':')){
703 			// Windows drive root
704 			tmp = g_strndup(p, &name[i+1] - p);
705 			p += 3;
706 		} else {
707 			tmp = g_strndup(p, &name[i] - p);
708 			p += &name[i] - p + 1;
709 		}
710 
711 		if(gtk_tree_model_iter_children(GTK_TREE_MODEL(directory_store), &iter, parent) == FALSE){
712 			LOG(LOG_DEBUG, "OUT : expand_to_path() : no children");
713 			return(FALSE);
714 		}
715 
716 		while(1){
717 			gchar *name;
718 
719 			gtk_tree_model_get(GTK_TREE_MODEL(directory_store), &iter, DIR_NAME_COLUMN, &name, -1);
720 			if(strcmp(name, tmp) == 0){
721 				if(parent) {
722 					gtk_tree_iter_free(parent);
723 				}
724 
725 				path = gtk_tree_model_get_path(GTK_TREE_MODEL(directory_store), &iter);
726 				if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(directory_view), path) == FALSE)
727 					gtk_tree_view_expand_row(GTK_TREE_VIEW(directory_view), path, FALSE);
728 				gtk_tree_path_free(path);
729 
730 				parent = gtk_tree_iter_copy(&iter);
731 				g_free(name);
732 				break;
733 			}
734 			if(gtk_tree_model_iter_next(GTK_TREE_MODEL(directory_store), &iter) == FALSE){
735 				LOG(LOG_DEBUG, "OUT : expand_to_path() : no such child");
736 				g_free(name);
737 				g_free(tmp);
738 				return(FALSE);
739 			}
740 		}
741 
742 		g_free(tmp);
743 
744 		if(name[i] == '\0')
745 			break;
746 	}
747 
748 	gtk_tree_store_set(GTK_TREE_STORE(directory_store),
749 			   parent,
750 			   DIR_ACTIVE_COLUMN, TRUE,
751 			   -1);
752 /*
753 	path = gtk_tree_model_get_path(GTK_TREE_MODEL(directory_store), parent);
754 	gtk_tree_view_collapse_row(GTK_TREE_VIEW(directory_view), path);
755 	gtk_tree_path_free(path);
756 */
757 
758 	gtk_tree_iter_free(parent);
759 
760 	LOG(LOG_DEBUG, "OUT : expand_to_path()");
761 
762 	return(TRUE);
763 }
764 
expand_history()765 static void expand_history()
766 {
767 	GList *l;
768 	GList *remove_list = NULL;
769 
770 	LOG(LOG_DEBUG, "IN : expand_history()");
771 
772 	l = g_list_first(active_dir_list);
773 	while(l){
774 		if(expand_to_path(l->data) == FALSE)
775 			remove_list = g_list_append(remove_list, l->data);
776 		l = g_list_next(l);
777 	}
778 
779 	l = g_list_first(remove_list);
780 	while(l){
781 		active_dir_list = g_list_remove(active_dir_list, l->data);
782 		LOG(LOG_DEBUG, "%s removed from history", l->data);
783 		g_free(l->data);
784 		l = g_list_next(l);
785 	}
786 
787 	if(remove_list != NULL){
788 		save_dirlist();
789 	}
790 
791 	g_list_free(remove_list);
792 
793 	LOG(LOG_DEBUG, "OUT : expand_history()");
794 }
795 
create_directory_tree()796 GtkWidget *create_directory_tree()
797 {
798 
799 	GtkWidget *scroll;
800 
801 	GtkCellRenderer *renderer;
802 	GtkTreeViewColumn *column;
803 	GtkTreeSelection *select;
804 
805 	LOG(LOG_DEBUG, "IN : create_directory_tree()");
806 
807 	pixbuf_file = create_pixbuf(IMAGE_FILE);
808 	pixbuf_folder_closed = create_pixbuf(IMAGE_FOLDER_CLOSED);
809 	pixbuf_folder_open = create_pixbuf(IMAGE_FOLDER_OPEN);
810 
811 
812 
813 	directory_store = gtk_tree_store_new(DIR_N_COLUMNS,
814 					     G_TYPE_BOOLEAN,
815 					     G_TYPE_BOOLEAN,
816 					     G_TYPE_OBJECT,
817 					     G_TYPE_OBJECT,
818 					     G_TYPE_OBJECT,
819 					     G_TYPE_STRING);
820 
821 
822 
823 	scroll = gtk_scrolled_window_new (NULL, NULL);
824 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
825 					GTK_POLICY_AUTOMATIC,
826 					GTK_POLICY_AUTOMATIC);
827 
828 	directory_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(directory_store));
829 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(directory_view), FALSE);
830 
831 	gtk_container_add (GTK_CONTAINER (scroll), directory_view);
832 
833 	g_signal_connect(G_OBJECT(directory_view),"row_expanded",
834 			 G_CALLBACK(row_expanded), (gpointer)NULL);
835 
836 	g_signal_connect(G_OBJECT(directory_view),"row_collapsed",
837 			 G_CALLBACK(row_collapsed), (gpointer)NULL);
838 
839 	g_signal_connect(G_OBJECT(directory_view),"button_press_event",
840 			 G_CALLBACK(button_press_event), (gpointer)NULL);
841 
842 
843 	renderer = gtk_cell_renderer_toggle_new();
844 	g_signal_connect (renderer, "toggled", G_CALLBACK(item_toggled), (gpointer)NULL);
845 
846 	// checkbox
847 #define TEST
848 #ifdef TEST
849 
850 	column = gtk_tree_view_column_new();
851 	gtk_tree_view_append_column (GTK_TREE_VIEW (directory_view), column);
852 
853 	gtk_tree_view_column_pack_start(column, renderer, FALSE);
854 	gtk_tree_view_column_add_attribute(column, renderer,
855 					   "active", DIR_ACTIVE_COLUMN);
856 	gtk_tree_view_column_add_attribute(column, renderer,
857 					   "activatable", DIR_ACTIVATABLE_COLUMN);
858 
859 
860 
861 	renderer = gtk_cell_renderer_pixbuf_new();
862 	gtk_tree_view_column_pack_start(column, renderer, FALSE);
863 
864 	gtk_tree_view_column_add_attribute(column, renderer,
865 					   "pixbuf", DIR_PIXBUF_COLUMN);
866 	gtk_tree_view_column_add_attribute(column, renderer,
867 					   "pixbuf-expander-closed", DIR_PIXBUF_CLOSED_COLUMN);
868 	gtk_tree_view_column_add_attribute(column, renderer,
869 					   "pixbuf-expander-open", DIR_PIXBUF_OPEN_COLUMN);
870 
871 
872 	renderer = gtk_cell_renderer_text_new();
873 	gtk_tree_view_column_pack_start(column, renderer, FALSE);
874 
875 	gtk_tree_view_column_add_attribute(column, renderer,
876 					   "text", DIR_NAME_COLUMN);
877 
878 
879 #else
880 
881 	column = gtk_tree_view_column_new_with_attributes(NULL,
882 							  renderer,
883 							  "active", DIR_ACTIVE_COLUMN,
884 							  "activatable", DIR_ACTIVATABLE_COLUMN,
885 							  NULL);
886 #endif
887 
888 	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE);
889 
890 	select = gtk_tree_view_get_selection (GTK_TREE_VIEW (directory_view));
891 	gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
892 
893 
894 
895 	// Show initial directory.
896 	show_directory();
897 
898 	// Expand and check formerly checked directories.
899 	expand_history();
900 
901 
902 	LOG(LOG_DEBUG, "OUT : create_directory_tree()");
903 
904 	return(scroll);
905 
906 }
907 
908 
get_active_dir_list()909 GList *get_active_dir_list()
910 {
911 	LOG(LOG_DEBUG, "IN : get_active_dir_list()");
912 	return(g_list_copy(active_dir_list));
913 }
914 
get_selected_directory()915 gchar *get_selected_directory()
916 {
917 	GtkTreeIter iter;
918 	GtkTreeSelection *selection;
919 	GtkTreePath *path;
920 	gchar *dirname;
921 
922 	LOG(LOG_DEBUG, "IN : get_selected_directory()");
923 
924 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(directory_view));
925 	if (gtk_tree_selection_get_selected(selection, NULL, &iter) == FALSE) {
926 		LOG(LOG_DEBUG, "OUT : get_selected_directory() = NULL");
927 		return(NULL);
928 	}
929 
930 	path = gtk_tree_model_get_path(GTK_TREE_MODEL(directory_store),
931 				       &iter);
932 
933 	dirname = compose_full_path(path);
934 	gtk_tree_path_free(path);
935 
936 	LOG(LOG_DEBUG, "OUT : get_selected_directory()");
937 	return(dirname);
938 }
939 
940 
refresh_directory_tree()941 void refresh_directory_tree()
942 {
943 
944 	LOG(LOG_DEBUG, "IN : reresh_directory_tree()");
945 
946 	if(directory_store == NULL)
947 		return;
948 
949 	gtk_tree_store_clear(GTK_TREE_STORE(directory_store));
950 
951 	show_directory();
952 	expand_history();
953 
954 	LOG(LOG_DEBUG, "OUT : reresh_directory_tree()");
955 
956 }
957