1999-09-09 Federico Mena Quintero <federico@redhat.com>
[midnight-commander.git] / src / tree.c
blob0912a220117ba8e48fc59ad486181b9f311d131e
1 /* Directory tree browser for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997 The Free Software Foundation
4 Written: 1994, 1996 Janne Kukonlehto
5 1997 Norbert Warmuth
6 1996, 1999 Miguel de Icaza
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This module has been converted to be a widget.
24 The program load and saves the tree each time the tree widget is
25 created and destroyed. This is required for the future vfs layer,
26 it will be possible to have tree views over virtual file systems.
29 #include <config.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include "tty.h"
34 #include "global.h"
35 #include "color.h"
36 #include "dialog.h"
37 #include "dir.h"
38 #include "dlg.h"
39 #include "widget.h"
40 #include "panel.h"
41 #include "mouse.h"
42 #include "main.h"
43 #include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
44 #include "fileopctx.h"
45 #include "help.h"
46 #include "key.h" /* For mi_getch() */
47 #include "tree.h"
48 #include "cmd.h"
49 #include "../vfs/vfs.h"
51 extern int command_prompt;
53 #define TREE_NORMALC HOT_FOCUSC
55 /* Specifies the display mode: 1d or 2d */
56 int tree_navigation_flag;
58 /* Forwards */
59 static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
60 #define tcallback (callback_fn) tree_callback
62 /* "$Id$" */
64 static tree_entry *back_ptr (tree_entry *ptr, int *count)
66 int i = 0;
68 while (ptr && ptr->prev && i < *count){
69 ptr = ptr->prev;
70 i ++;
72 *count = i;
73 return ptr;
76 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
78 int i = 0;
80 while (ptr && ptr->next && i < *count){
81 ptr = ptr->next;
82 i ++;
84 *count = i;
85 return ptr;
88 /* Add a directory to the list of directories */
89 tree_entry *tree_add_entry (WTree *tree, char *name)
91 if (!tree)
92 return 0;
94 return tree_store_add_entry (name);
97 #if 0
98 /* Append a directory to the list of directories */
99 static tree_entry *tree_append_entry (WTree *tree, char *name)
101 tree_entry *current, *new;
102 int i, len;
103 int submask = 0;
105 /* We assume the directory is not yet in the list */
107 new = g_new (tree_entry, 1);
108 if (!tree->store->tree_first){
109 /* Empty list */
110 tree->store->tree_first = new;
111 new->prev = NULL;
112 } else {
113 tree->tree_last->next = new;
114 new->prev = tree->tree_last;
116 new->next = NULL;
117 tree->store->tree_last = new;
119 /* Calculate attributes */
120 new->name = g_strdup (name);
121 len = strlen (new->name);
122 new->sublevel = 0;
123 for (i = 0; i < len; i++)
124 if (new->name [i] == PATH_SEP){
125 new->sublevel++;
126 new->subname = new->name + i + 1;
128 submask = 1 << new->sublevel;
129 submask &= (2 << new->sublevel) - 1;
130 new->submask = submask;
131 new->mark = 0;
133 /* Correct the submasks of the previous entries */
134 current = new->prev;
135 while (current && current->sublevel > new->sublevel){
136 current->submask |= 1 << new->sublevel;
137 current = current->prev;
140 /* The entry has now been appended */
141 return new;
143 #endif
145 void
146 remove_callback (tree_entry *entry, void *data)
148 WTree *tree = data;
150 if (tree->selected_ptr == entry){
151 if (tree->selected_ptr->next)
152 tree->selected_ptr = tree->selected_ptr->next;
153 else
154 tree->selected_ptr = tree->selected_ptr->prev;
158 void tree_remove_entry (WTree *tree, char *name)
160 tree_store_remove_entry (name);
163 void tree_destroy (WTree *tree)
165 tree_store_remove_entry_remove_hook (remove_callback);
166 save_tree (tree);
167 tree_store_destroy ();
169 if (tree->tree_shown){
170 g_free (tree->tree_shown);
171 tree->tree_shown = 0;
173 tree->selected_ptr = NULL;
176 /* Loads the .mc.tree file */
177 void load_tree (WTree *tree)
179 tree_store_load ();
181 tree->selected_ptr = tree->store->tree_first;
182 tree_chdir (tree, home_dir);
185 /* Save the .mc.tree file */
186 void save_tree (WTree *tree)
188 int error;
190 error = tree_store_save ();
192 if (error){
193 fprintf (stderr, _("Can't open the %s file for writing:\n%s\n"), MC_TREE,
194 unix_error_string (error));
195 return;
199 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
201 Dlg_head *h = tree->widget.parent;
202 int line;
204 /* Show mini info */
205 if (tree->is_panel){
206 if (!show_mini_info)
207 return;
208 line = tree_lines+2;
209 } else
210 line = tree_lines+1;
212 widget_move (&tree->widget, line, 1);
213 hline (' ', tree_cols);
214 widget_move (&tree->widget, line, 1);
216 if (tree->searching){
217 /* Show search string */
218 attrset (TREE_NORMALC);
219 attrset (FOCUSC);
220 addch (PATH_SEP);
222 addstr (name_trunc (tree->search_buffer, tree_cols-2));
223 addch (' ');
224 attrset (FOCUSC);
225 } else {
226 /* Show full name of selected directory */
227 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
231 void show_tree (WTree *tree)
233 Dlg_head *h = tree->widget.parent;
234 tree_entry *current;
235 int i, j, topsublevel;
236 int x, y;
237 int tree_lines, tree_cols;
239 /* Initialize */
240 x = y = 0;
241 tree_lines = tlines (tree);
242 tree_cols = tree->widget.cols;
244 attrset (TREE_NORMALC);
245 widget_move ((Widget*)tree, y, x);
246 if (tree->is_panel){
247 tree_cols -= 2;
248 x = y = 1;
251 if (tree->tree_shown)
252 g_free (tree->tree_shown);
253 tree->tree_shown = g_new (tree_entry*, tree_lines);
255 for (i = 0; i < tree_lines; i++)
256 tree->tree_shown [i] = NULL;
257 if (tree->store->tree_first)
258 topsublevel = tree->store->tree_first->sublevel;
259 else
260 topsublevel = 0;
261 if (!tree->selected_ptr){
262 tree->selected_ptr = tree->store->tree_first;
263 tree->topdiff = 0;
265 current = tree->selected_ptr;
267 /* Calculate the directory which is to be shown on the topmost line */
268 if (tree_navigation_flag){
269 i = 0;
270 while (current->prev && i < tree->topdiff){
271 current = current->prev;
272 if (current->sublevel < tree->selected_ptr->sublevel){
273 if (strncmp (current->name, tree->selected_ptr->name,
274 strlen (current->name)) == 0)
275 i++;
276 } else if (current->sublevel == tree->selected_ptr->sublevel){
277 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
278 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
279 i++;
280 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
281 && strlen (tree->selected_ptr->name) > 1){
282 if (strncmp (current->name, tree->selected_ptr->name,
283 strlen (tree->selected_ptr->name)) == 0)
284 i++;
287 tree->topdiff = i;
288 } else
289 current = back_ptr (current, &tree->topdiff);
291 /* Loop for every line */
292 for (i = 0; i < tree_lines; i++){
293 /* Move to the beginning of the line */
294 widget_move (&tree->widget, y+i, x);
296 hline (' ', tree_cols);
297 widget_move (&tree->widget, y+i, x);
299 if (!current)
300 continue;
302 tree->tree_shown [i] = current;
303 if (current->sublevel == topsublevel){
305 /* Top level directory */
306 if (tree->active && current == tree->selected_ptr) {
307 if (!use_colors && !tree->is_panel)
308 attrset (MARKED_COLOR);
309 else
310 attrset (SELECTED_COLOR);
313 /* Show full name */
314 addstr (name_trunc (current->name, tree_cols - 6));
315 } else{
316 /* Sub level directory */
318 acs ();
319 /* Output branch parts */
320 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
321 if (tree_cols - 8 - 3 * j < 9)
322 break;
323 addch (' ');
324 if (current->submask & (1 << (j + topsublevel + 1)))
325 addch (ACS_VLINE);
326 else
327 addch (' ');
328 addch (' ');
330 addch (' '); j++;
331 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
332 addch (ACS_LLCORNER);
333 else
334 addch (ACS_LTEE);
335 addch (ACS_HLINE);
336 noacs ();
338 if (tree->active && current == tree->selected_ptr) {
339 /* Selected directory -> change color */
340 if (!use_colors && !tree->is_panel)
341 attrset (MARKED_COLOR);
342 else
343 attrset (SELECTED_COLOR);
346 /* Show sub-name */
347 addch (' ');
348 addstr (name_trunc (current->subname,
349 tree_cols - 2 - 4 - 3 * j));
351 addch (' ');
353 /* Return to normal color */
354 attrset (TREE_NORMALC);
356 /* Calculate the next value for current */
357 if (tree_navigation_flag){
358 current = current->next;
359 while (current){
360 if (current->sublevel < tree->selected_ptr->sublevel){
361 if (strncmp (current->name, tree->selected_ptr->name,
362 strlen (current->name)) == 0)
363 break;
364 } else if (current->sublevel == tree->selected_ptr->sublevel){
365 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
366 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
367 break;
368 } else if (current->sublevel == tree->selected_ptr->sublevel+1
369 && strlen (tree->selected_ptr->name) > 1){
370 if (strncmp (current->name, tree->selected_ptr->name,
371 strlen (tree->selected_ptr->name)) == 0)
372 break;
374 current = current->next;
376 } else
377 current = current->next;
379 tree_show_mini_info (tree, tree_lines, tree_cols);
382 static void check_focus (WTree *tree)
384 if (tree->topdiff < 3)
385 tree->topdiff = 3;
386 else if (tree->topdiff >= tlines (tree) - 3)
387 tree->topdiff = tlines (tree) - 3 - 1;
390 void tree_move_backward (WTree *tree, int i)
392 tree_entry *current;
393 int j = 0;
395 if (tree_navigation_flag){
396 current = tree->selected_ptr;
397 while (j < i && current->prev
398 && current->prev->sublevel >= tree->selected_ptr->sublevel){
399 current = current->prev;
400 if (current->sublevel == tree->selected_ptr->sublevel){
401 tree->selected_ptr = current;
402 j ++;
405 i = j;
406 } else
407 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
408 tree->topdiff -= i;
409 check_focus (tree);
412 void tree_move_forward (WTree *tree, int i)
414 tree_entry *current;
415 int j = 0;
417 if (tree_navigation_flag){
418 current = tree->selected_ptr;
419 while (j < i && current->next
420 && current->next->sublevel >= tree->selected_ptr->sublevel){
421 current = current->next;
422 if (current->sublevel == tree->selected_ptr->sublevel){
423 tree->selected_ptr = current;
424 j ++;
427 i = j;
428 } else
429 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
430 tree->topdiff += i;
431 check_focus (tree);
434 void tree_move_to_child (WTree *tree)
436 tree_entry *current;
438 /* Do we have a starting point? */
439 if (!tree->selected_ptr)
440 return;
441 /* Take the next entry */
442 current = tree->selected_ptr->next;
443 /* Is it the child of the selected entry */
444 if (current && current->sublevel > tree->selected_ptr->sublevel){
445 /* Yes -> select this entry */
446 tree->selected_ptr = current;
447 tree->topdiff++;
448 check_focus (tree);
449 } else {
450 /* No -> rescan and try again */
451 tree_rescan_cmd (tree);
452 current = tree->selected_ptr->next;
453 if (current && current->sublevel > tree->selected_ptr->sublevel){
454 tree->selected_ptr = current;
455 tree->topdiff++;
456 check_focus (tree);
461 int tree_move_to_parent (WTree *tree)
463 tree_entry *current;
464 tree_entry *old;
466 if (!tree->selected_ptr)
467 return 0;
468 old = tree->selected_ptr;
469 current = tree->selected_ptr->prev;
470 while (current && current->sublevel >= tree->selected_ptr->sublevel){
471 current = current->prev;
472 tree->topdiff--;
474 if (!current)
475 current = tree->store->tree_first;
476 tree->selected_ptr = current;
477 check_focus (tree);
478 return tree->selected_ptr != old;
481 void tree_move_to_top (WTree *tree)
483 tree->selected_ptr = tree->store->tree_first;
484 tree->topdiff = 0;
487 void tree_move_to_bottom (WTree *tree)
489 tree->selected_ptr = tree->store->tree_last;
490 tree->topdiff = tlines (tree) - 3 - 1;
493 void tree_chdir (WTree *tree, char *dir)
495 tree_entry *current;
497 current = tree_store_whereis (dir);
498 if (current){
499 tree->selected_ptr = current;
500 check_focus (tree);
504 void
505 sync_tree (char *path)
507 tree_chdir (the_tree, path);
510 /* Handle mouse click */
511 void tree_event (WTree *tree, int y)
513 if (tree->tree_shown [y]){
514 tree->selected_ptr = tree->tree_shown [y];
515 tree->topdiff = y;
517 show_tree (tree);
520 static void chdir_sel (WTree *tree);
522 static void maybe_chdir (WTree *tree)
524 if (!(xtree_mode && tree->is_panel))
525 return;
526 if (is_idle ())
527 chdir_sel (tree);
530 /* Mouse callback */
531 static int event_callback (Gpm_Event *event, WTree *tree)
533 if (!(event->type & GPM_UP))
534 return MOU_ENDLOOP;
536 if (tree->is_panel)
537 event->y--;
539 event->y--;
541 if (!tree->active)
542 change_panel ();
544 if (event->y < 0){
545 tree_move_backward (tree, tlines (tree) - 1);
546 show_tree (tree);
548 else if (event->y >= tlines (tree)){
549 tree_move_forward (tree, tlines (tree) - 1);
550 show_tree (tree);
551 } else {
552 tree_event (tree, event->y);
553 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
554 chdir_sel (tree);
557 return MOU_ENDLOOP;
560 /* Search tree for text */
561 int search_tree (WTree *tree, char *text)
563 tree_entry *current;
564 int len;
565 int wrapped = 0;
566 int found = 0;
568 len = strlen (text);
569 current = tree->selected_ptr;
570 found = 0;
571 while (!wrapped || current != tree->selected_ptr){
572 if (strncmp (current->subname, text, len) == 0){
573 tree->selected_ptr = current;
574 found = 1;
575 break;
577 current = current->next;
578 if (!current){
579 current = tree->store->tree_first;
580 wrapped = 1;
582 tree->topdiff++;
584 check_focus (tree);
585 return found;
588 static void tree_do_search (WTree *tree, int key)
590 int l;
592 l = strlen (tree->search_buffer);
593 if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
594 tree->search_buffer [--l] = 0;
595 else {
596 if (key && l < sizeof (tree->search_buffer)){
597 tree->search_buffer [l] = key;
598 tree->search_buffer [l+1] = 0;
599 l++;
603 if (!search_tree (tree, tree->search_buffer))
604 tree->search_buffer [--l] = 0;
606 show_tree (tree);
607 maybe_chdir (tree);
610 void tree_rescan_cmd (WTree *tree)
612 char old_dir [MC_MAXPATHLEN];
614 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
615 mc_chdir (tree->selected_ptr->name))
616 return;
618 tree_store_rescan (tree->selected_ptr->name);
619 mc_chdir (old_dir);
622 int tree_forget_cmd (WTree *tree)
624 if (tree->selected_ptr)
625 tree_remove_entry (tree, tree->selected_ptr->name);
626 return 1;
629 void tree_copy (WTree *tree, char *default_dest)
631 char *dest;
632 long count = 0;
633 double bytes = 0;
634 FileOpContext *ctx;
636 if (!tree->selected_ptr)
637 return;
638 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
639 name_trunc (tree->selected_ptr->name, 50));
640 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
641 if (!dest || !*dest){
642 return;
645 ctx = file_op_context_new ();
646 file_op_context_create_ui (ctx, OP_COPY, FALSE);
647 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
648 file_op_context_destroy (ctx);
650 g_free (dest);
653 static void tree_help_cmd (void)
655 char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
656 interactive_display (hlpfile, "[Directory Tree]");
657 g_free (hlpfile);
660 static int tree_copy_cmd (WTree *tree)
662 tree_copy (tree, "");
663 return 1;
666 void tree_move (WTree *tree, char *default_dest)
668 char *dest;
669 struct stat buf;
670 double bytes = 0;
671 long count = 0;
672 FileOpContext *ctx;
674 if (!tree->selected_ptr)
675 return;
676 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
677 name_trunc (tree->selected_ptr->name, 50));
678 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
679 if (!dest || !*dest){
680 return;
682 if (stat (dest, &buf)){
683 message (1, _(" Error "), _(" Can't stat the destination \n %s "),
684 unix_error_string (errno));
685 g_free (dest);
686 return;
688 if (!S_ISDIR (buf.st_mode)){
689 message (1, _(" Error "), _(" The destination isn't a directory "));
690 g_free (dest);
691 return;
694 ctx = file_op_context_new ();
695 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
696 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
697 file_op_context_destroy (ctx);
699 g_free (dest);
702 static int
703 tree_move_cmd (WTree *tree)
705 tree_move (tree, "");
706 return 1;
709 static int
710 tree_mkdir_cmd (WTree *tree)
712 char old_dir [MC_MAXPATHLEN];
714 if (!tree->selected_ptr)
715 return 0;
716 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
717 return 0;
718 if (chdir (tree->selected_ptr->name))
719 return 0;
720 /* FIXME
721 mkdir_cmd (tree);
723 tree_rescan_cmd (tree);
724 chdir (old_dir);
725 return 1;
728 static void
729 tree_rmdir_cmd (WTree *tree)
731 char old_dir [MC_MAXPATHLEN];
732 long count = 0;
733 double bytes = 0;
734 FileOpContext *ctx;
736 if (tree->selected_ptr){
737 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
738 return;
739 if (mc_chdir (PATH_SEP_STR))
740 return;
741 if (confirm_delete){
742 char *buf;
743 int result;
745 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
746 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
747 g_free (buf);
748 if (result != 0){
749 return;
753 ctx = file_op_context_new ();
754 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
755 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
756 tree_forget_cmd (tree);
757 file_op_context_destroy (ctx);
758 mc_chdir (old_dir);
759 return;
760 } else
761 return;
764 static void set_navig_label (Dlg_head *h);
766 static void
767 tree_toggle_navig (Dlg_head *h)
769 tree_navigation_flag = 1 - tree_navigation_flag;
770 set_navig_label (h);
773 void
774 set_navig_label (Dlg_head *h)
776 define_label_data (h, (Widget *)tree,
777 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
778 (void (*)(void *))tree_toggle_navig, h);
781 static void
782 move_down (WTree *tree)
784 tree_move_forward (tree, 1);
785 show_tree (tree);
786 maybe_chdir (tree);
789 static void
790 move_up (WTree *tree)
792 tree_move_backward (tree, 1);
793 show_tree (tree);
794 maybe_chdir (tree);
797 static void
798 move_home (WTree *tree)
800 tree_move_to_top (tree);
801 show_tree (tree);
802 maybe_chdir (tree);
805 static void
806 move_end (WTree *tree)
808 tree_move_to_bottom (tree);
809 show_tree (tree);
810 maybe_chdir (tree);
813 static int
814 move_left (WTree *tree)
816 int v;
818 if (tree_navigation_flag){
819 v = tree_move_to_parent (tree);
820 show_tree (tree);
821 maybe_chdir (tree);
822 return v;
824 return 0;
827 static int
828 move_right (WTree *tree)
830 if (tree_navigation_flag){
831 tree_move_to_child (tree);
832 show_tree (tree);
833 maybe_chdir (tree);
834 return 1;
836 return 0;
839 static void
840 move_prevp (WTree *tree)
842 tree_move_backward (tree, tlines (tree) - 1);
843 show_tree (tree);
844 maybe_chdir (tree);
847 static void
848 move_nextp (WTree *tree)
850 tree_move_forward (tree, tlines (tree) - 1);
851 show_tree (tree);
852 maybe_chdir (tree);
855 static void
856 chdir_sel (WTree *tree)
858 if (!tree->is_panel){
859 tree->done = 1;
860 return;
862 change_panel ();
863 if (do_cd (tree->selected_ptr->name, cd_exact)){
864 paint_panel (cpanel);
865 select_item (cpanel);
866 } else {
867 message (1, MSG_ERROR, _(" Can't chdir to \"%s\" \n %s "),
868 tree->selected_ptr->name, unix_error_string (errno));
870 change_panel ();
871 show_tree (tree);
872 return;
875 static void
876 tree_start_search (WTree *tree)
878 int i;
880 if (tree->searching){
882 if (tree->selected_ptr == tree->store->tree_last)
883 tree_move_to_top(tree);
884 else {
885 /* set navigation mode temporarily to 'Static' because in
886 * dynamic navigation mode tree_move_forward will not move
887 * to a lower sublevel if necessary (sequent searches must
888 * start with the directory followed the last found directory)
890 i = tree_navigation_flag;
891 tree_navigation_flag = 0;
892 tree_move_forward (tree, 1);
893 tree_navigation_flag = i;
895 tree_do_search (tree, 0);
897 else {
898 tree->searching = 1;
899 tree->search_buffer[0] = 0;
903 static key_map tree_keymap [] = {
904 { XCTRL('n'), move_down },
905 { XCTRL('p'), move_up },
906 { KEY_DOWN, move_down },
907 { KEY_UP, move_up },
908 { '\n', chdir_sel },
909 { KEY_ENTER, chdir_sel },
910 { KEY_HOME, move_home },
911 { KEY_C1, move_end },
912 { KEY_END, move_end },
913 { KEY_A1, move_home },
914 { KEY_NPAGE, move_nextp },
915 { KEY_PPAGE, move_prevp },
916 { XCTRL('v'), move_nextp },
917 { ALT('v'), move_prevp },
918 { XCTRL('p'), move_up },
919 { XCTRL('p'), move_down },
920 { XCTRL('s'), tree_start_search },
921 { ALT('s'), tree_start_search },
922 { XCTRL('r'), tree_rescan_cmd },
923 { KEY_DC, tree_rmdir_cmd },
924 { 0, 0 }
927 static inline int
928 tree_key (WTree *tree, int key)
930 int i;
932 for (i = 0; tree_keymap [i].key_code; i++){
933 if (key == tree_keymap [i].key_code){
934 if (tree_keymap [i].fn != tree_start_search)
935 tree->searching = 0;
936 (*tree_keymap [i].fn)(tree);
937 show_tree (tree);
938 return 1;
942 /* We do not want to use them if we do not need to */
943 /* Input line may want to take the motion key event */
944 if (key == KEY_LEFT)
945 return move_left (tree);
947 if (key == KEY_RIGHT)
948 return move_right (tree);
950 if (is_abort_char (key)) {
951 if (tree->is_panel) {
952 tree->searching = 0;
953 show_tree (tree);
954 return 1; /* eat abort char */
956 return 0; /* modal tree dialog: let upper layer see the
957 abort character and close the dialog */
960 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
961 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
962 if (tree->searching){
963 tree_do_search (tree, key);
964 show_tree (tree);
965 return 1;
968 if (!command_prompt) {
969 tree_start_search (tree);
970 tree_do_search (tree, key);
971 return 1;
973 return tree->is_panel;
976 return 0;
979 static void
980 tree_frame (Dlg_head *h, WTree *tree)
982 attrset (NORMAL_COLOR);
983 widget_erase ((Widget*) tree);
984 if (tree->is_panel)
985 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
986 tree->widget.cols);
988 if (show_mini_info && tree->is_panel){
989 widget_move (tree, tlines (tree) + 1, 1);
990 hline (ACS_HLINE, tree->widget.cols - 2);
995 static int
996 tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
998 switch (msg){
999 case WIDGET_DRAW:
1000 tree_frame (h, tree);
1001 show_tree (tree);
1002 return 1;
1004 case WIDGET_KEY:
1005 return tree_key (tree, par);
1007 case WIDGET_FOCUS:
1008 tree->active = 1;
1009 define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
1010 define_label_data (h, (Widget *)tree,
1011 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
1012 define_label_data (h, (Widget *)tree,
1013 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
1014 define_label_data (h, (Widget *)tree,
1015 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
1016 define_label_data (h, (Widget *)tree,
1017 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1018 #if 0
1019 /* FIXME: mkdir is currently defunct */
1020 define_label_data (h, (Widget *)tree,
1021 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1022 #else
1023 define_label (h, (Widget *)tree, 7, "", 0);
1024 #endif
1025 define_label_data (h, (Widget *)tree,
1026 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
1027 set_navig_label (h);
1028 redraw_labels (h, (Widget *)tree);
1031 /* FIXME: Should find a better way of only displaying the
1032 currently selected item */
1033 show_tree (tree);
1034 return 1;
1036 /* FIXME: Should find a better way of changing the color of the
1037 selected item */
1038 case WIDGET_UNFOCUS:
1039 tree->active = 0;
1040 show_tree (tree);
1041 return 1;
1043 return default_proc (h, msg, par);
1046 WTree *
1047 tree_new (int is_panel, int y, int x, int lines, int cols)
1049 WTree *tree = g_new (WTree, 1);
1051 init_widget (&tree->widget, y, x, lines, cols, tcallback,
1052 (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
1053 tree->is_panel = is_panel;
1054 tree->selected_ptr = 0;
1056 tree->store = tree_store_init ();
1057 tree_store_add_entry_remove_hook (remove_callback, tree);
1058 tree->tree_shown = 0;
1059 tree->search_buffer [0] = 0;
1060 tree->topdiff = tree->widget.lines / 2;
1061 tree->searching = 0;
1062 tree->done = 0;
1063 tree->active = 0;
1065 /* We do not want to keep the cursor */
1066 widget_want_cursor (tree->widget, 0);
1067 load_tree (tree);
1068 return tree;