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