updated the .TP cleanup for coherency in the key description pages.
[midnight-commander.git] / src / tree.c
blob8119b113f29d9d49a85bab788918ba70cef0edcc
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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>
34 #include "global.h"
35 #include "tty.h"
36 #include "color.h"
37 #include "dialog.h"
38 #include "dir.h"
39 #include "dlg.h"
40 #include "widget.h"
41 #include "panel.h"
42 #include "mouse.h"
43 #include "main.h"
44 #include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
45 #include "fileopctx.h"
46 #include "help.h"
47 #include "key.h" /* For mi_getch() */
48 #include "tree.h"
49 #include "cmd.h"
50 #include "../vfs/vfs.h"
52 extern int command_prompt;
54 /* Use the color of the parent widget for the unselected entries */
55 #define TREE_NORMALC NORMALC
57 /* Specifies the display mode: 1d or 2d */
58 static int tree_navigation_flag;
60 /* Forwards */
61 static void save_tree (WTree *tree);
62 static void tree_rescan_cmd (WTree *tree);
63 static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
64 #define tcallback (callback_fn) tree_callback
66 static tree_entry *back_ptr (tree_entry *ptr, int *count)
68 int i = 0;
70 while (ptr && ptr->prev && i < *count){
71 ptr = ptr->prev;
72 i ++;
74 *count = i;
75 return ptr;
78 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
80 int i = 0;
82 while (ptr && ptr->next && i < *count){
83 ptr = ptr->next;
84 i ++;
86 *count = i;
87 return ptr;
90 #if 0
91 /* Add a directory to the list of directories */
92 static tree_entry *tree_add_entry (WTree *tree, char *name)
94 if (!tree)
95 return 0;
97 return tree_store_add_entry (name);
100 /* Append a directory to the list of directories */
101 static tree_entry *tree_append_entry (WTree *tree, char *name)
103 tree_entry *current, *new;
104 int i, len;
105 int submask = 0;
107 /* We assume the directory is not yet in the list */
109 new = g_new (tree_entry, 1);
110 if (!tree->store->tree_first){
111 /* Empty list */
112 tree->store->tree_first = new;
113 new->prev = NULL;
114 } else {
115 tree->tree_last->next = new;
116 new->prev = tree->tree_last;
118 new->next = NULL;
119 tree->store->tree_last = new;
121 /* Calculate attributes */
122 new->name = g_strdup (name);
123 len = strlen (new->name);
124 new->sublevel = 0;
125 for (i = 0; i < len; i++)
126 if (new->name [i] == PATH_SEP){
127 new->sublevel++;
128 new->subname = new->name + i + 1;
130 submask = 1 << new->sublevel;
131 submask &= (2 << new->sublevel) - 1;
132 new->submask = submask;
133 new->mark = 0;
135 /* Correct the submasks of the previous entries */
136 current = new->prev;
137 while (current && current->sublevel > new->sublevel){
138 current->submask |= 1 << new->sublevel;
139 current = current->prev;
142 /* The entry has now been appended */
143 return new;
145 #endif
147 static void
148 remove_callback (tree_entry *entry, void *data)
150 WTree *tree = data;
152 if (tree->selected_ptr == entry){
153 if (tree->selected_ptr->next)
154 tree->selected_ptr = tree->selected_ptr->next;
155 else
156 tree->selected_ptr = tree->selected_ptr->prev;
160 static void tree_remove_entry (WTree *tree, char *name)
162 tree_store_remove_entry (name);
165 static void tree_destroy (WTree *tree)
167 tree_store_remove_entry_remove_hook (remove_callback);
168 save_tree (tree);
170 if (tree->tree_shown){
171 g_free (tree->tree_shown);
172 tree->tree_shown = 0;
174 tree->selected_ptr = NULL;
177 /* Loads the .mc.tree file */
178 static void load_tree (WTree *tree)
180 tree_store_load ();
182 tree->selected_ptr = tree->store->tree_first;
183 tree_chdir (tree, home_dir);
186 /* Save the .mc.tree file */
187 static void save_tree (WTree *tree)
189 int error;
191 error = tree_store_save ();
193 if (error){
194 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
195 unix_error_string (error));
196 return;
200 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
202 Dlg_head *h = tree->widget.parent;
203 int line;
205 /* Show mini info */
206 if (tree->is_panel){
207 if (!show_mini_info)
208 return;
209 line = tree_lines+2;
210 } else
211 line = tree_lines+1;
213 widget_move (&tree->widget, line, 1);
214 hline (' ', tree_cols);
215 widget_move (&tree->widget, line, 1);
217 if (tree->searching){
218 /* Show search string */
219 attrset (TREE_NORMALC);
220 attrset (FOCUSC);
221 addch (PATH_SEP);
223 addstr (name_trunc (tree->search_buffer, tree_cols-2));
224 addch (' ');
225 attrset (FOCUSC);
226 } else {
227 /* Show full name of selected directory */
228 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
232 static void show_tree (WTree *tree)
234 Dlg_head *h = tree->widget.parent;
235 tree_entry *current;
236 int i, j, topsublevel;
237 int x, y;
238 int tree_lines, tree_cols;
240 /* Initialize */
241 x = y = 0;
242 tree_lines = tlines (tree);
243 tree_cols = tree->widget.cols;
245 attrset (TREE_NORMALC);
246 widget_move ((Widget*)tree, y, x);
247 if (tree->is_panel){
248 tree_cols -= 2;
249 x = y = 1;
252 if (tree->tree_shown)
253 g_free (tree->tree_shown);
254 tree->tree_shown = g_new (tree_entry*, tree_lines);
256 for (i = 0; i < tree_lines; i++)
257 tree->tree_shown [i] = NULL;
258 if (tree->store->tree_first)
259 topsublevel = tree->store->tree_first->sublevel;
260 else
261 topsublevel = 0;
262 if (!tree->selected_ptr){
263 tree->selected_ptr = tree->store->tree_first;
264 tree->topdiff = 0;
266 current = tree->selected_ptr;
268 /* Calculate the directory which is to be shown on the topmost line */
269 if (tree_navigation_flag){
270 i = 0;
271 while (current->prev && i < tree->topdiff){
272 current = current->prev;
273 if (current->sublevel < tree->selected_ptr->sublevel){
274 if (strncmp (current->name, tree->selected_ptr->name,
275 strlen (current->name)) == 0)
276 i++;
277 } else if (current->sublevel == tree->selected_ptr->sublevel){
278 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
279 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
280 i++;
281 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
282 && strlen (tree->selected_ptr->name) > 1){
283 if (strncmp (current->name, tree->selected_ptr->name,
284 strlen (tree->selected_ptr->name)) == 0)
285 i++;
288 tree->topdiff = i;
289 } else
290 current = back_ptr (current, &tree->topdiff);
292 /* Loop for every line */
293 for (i = 0; i < tree_lines; i++){
294 /* Move to the beginning of the line */
295 widget_move (&tree->widget, y+i, x);
297 hline (' ', tree_cols);
298 widget_move (&tree->widget, y+i, x);
300 if (!current)
301 continue;
303 tree->tree_shown [i] = current;
304 if (current->sublevel == topsublevel){
306 /* Top level directory */
307 if (tree->active && current == tree->selected_ptr) {
308 if (!use_colors && !tree->is_panel)
309 attrset (MARKED_COLOR);
310 else
311 attrset (SELECTED_COLOR);
314 /* Show full name */
315 addstr (name_trunc (current->name, tree_cols - 6));
316 } else{
317 /* Sub level directory */
319 acs ();
320 /* Output branch parts */
321 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
322 if (tree_cols - 8 - 3 * j < 9)
323 break;
324 addch (' ');
325 if (current->submask & (1 << (j + topsublevel + 1)))
326 addch (ACS_VLINE);
327 else
328 addch (' ');
329 addch (' ');
331 addch (' '); j++;
332 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
333 addch (ACS_LLCORNER);
334 else
335 addch (ACS_LTEE);
336 addch (ACS_HLINE);
337 noacs ();
339 if (tree->active && current == tree->selected_ptr) {
340 /* Selected directory -> change color */
341 if (!use_colors && !tree->is_panel)
342 attrset (MARKED_COLOR);
343 else
344 attrset (SELECTED_COLOR);
347 /* Show sub-name */
348 addch (' ');
349 addstr (name_trunc (current->subname,
350 tree_cols - 2 - 4 - 3 * j));
352 addch (' ');
354 /* Return to normal color */
355 attrset (TREE_NORMALC);
357 /* Calculate the next value for current */
358 current = current->next;
359 if (tree_navigation_flag){
360 while (current){
361 if (current->sublevel < tree->selected_ptr->sublevel){
362 if (strncmp (current->name, tree->selected_ptr->name,
363 strlen (current->name)) == 0)
364 break;
365 } else if (current->sublevel == tree->selected_ptr->sublevel){
366 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
367 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
368 break;
369 } else if (current->sublevel == tree->selected_ptr->sublevel+1
370 && strlen (tree->selected_ptr->name) > 1){
371 if (strncmp (current->name, tree->selected_ptr->name,
372 strlen (tree->selected_ptr->name)) == 0)
373 break;
375 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 static 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 static 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 static 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 static 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 static void tree_move_to_top (WTree *tree)
483 tree->selected_ptr = tree->store->tree_first;
484 tree->topdiff = 0;
487 static 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 static 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_NORMAL;
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_NORMAL;
560 /* Search tree for text */
561 static 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 static 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 static int tree_forget_cmd (WTree *tree)
624 if (tree->selected_ptr)
625 tree_remove_entry (tree, tree->selected_ptr->name);
626 return 1;
629 static void tree_copy (WTree *tree, char *default_dest)
631 char *dest;
632 off_t 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);
642 if (!dest)
643 return;
645 if (!*dest){
646 g_free (dest);
647 return;
650 ctx = file_op_context_new ();
651 file_op_context_create_ui (ctx, OP_COPY, FALSE);
652 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
653 file_op_context_destroy (ctx);
655 g_free (dest);
658 static void tree_help_cmd (void)
660 interactive_display (NULL, "[Directory Tree]");
663 static int tree_copy_cmd (WTree *tree)
665 tree_copy (tree, "");
666 return 1;
669 static void tree_move (WTree *tree, char *default_dest)
671 char *dest;
672 struct stat buf;
673 double bytes = 0;
674 off_t count = 0;
675 FileOpContext *ctx;
677 if (!tree->selected_ptr)
678 return;
679 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
680 name_trunc (tree->selected_ptr->name, 50));
681 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
682 if (!dest)
683 return;
684 if (!*dest){
685 g_free (dest);
686 return;
688 if (stat (dest, &buf)){
689 message (1, MSG_ERROR, _(" Cannot stat the destination \n %s "),
690 unix_error_string (errno));
691 g_free (dest);
692 return;
694 if (!S_ISDIR (buf.st_mode)){
695 message (1, MSG_ERROR, _(" The destination isn't a directory "));
696 g_free (dest);
697 return;
700 ctx = file_op_context_new ();
701 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
702 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
703 file_op_context_destroy (ctx);
705 g_free (dest);
708 static int
709 tree_move_cmd (WTree *tree)
711 tree_move (tree, "");
712 return 1;
715 #if 0
716 static int
717 tree_mkdir_cmd (WTree *tree)
719 char old_dir [MC_MAXPATHLEN];
721 if (!tree->selected_ptr)
722 return 0;
723 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
724 return 0;
725 if (chdir (tree->selected_ptr->name))
726 return 0;
727 /* FIXME
728 mkdir_cmd (tree);
730 tree_rescan_cmd (tree);
731 chdir (old_dir);
732 return 1;
734 #endif
736 static void
737 tree_rmdir_cmd (WTree *tree)
739 char old_dir [MC_MAXPATHLEN];
740 off_t count = 0;
741 double bytes = 0;
742 FileOpContext *ctx;
744 if (tree->selected_ptr){
745 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
746 return;
747 if (mc_chdir (PATH_SEP_STR))
748 return;
749 if (confirm_delete){
750 char *buf;
751 int result;
753 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
754 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
755 g_free (buf);
756 if (result != 0){
757 return;
761 ctx = file_op_context_new ();
762 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
763 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
764 tree_forget_cmd (tree);
765 file_op_context_destroy (ctx);
766 mc_chdir (old_dir);
767 return;
768 } else
769 return;
772 static void set_navig_label (WTree *tree);
774 static void
775 tree_toggle_navig (WTree *tree)
777 tree_navigation_flag = 1 - tree_navigation_flag;
778 set_navig_label (tree);
781 static void
782 set_navig_label (WTree *tree)
784 define_label_data (tree->widget.parent, (Widget *) tree,
785 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
786 (buttonbarfn) tree_toggle_navig, tree);
789 static void
790 move_down (WTree *tree)
792 tree_move_forward (tree, 1);
793 show_tree (tree);
794 maybe_chdir (tree);
797 static void
798 move_up (WTree *tree)
800 tree_move_backward (tree, 1);
801 show_tree (tree);
802 maybe_chdir (tree);
805 static void
806 move_home (WTree *tree)
808 tree_move_to_top (tree);
809 show_tree (tree);
810 maybe_chdir (tree);
813 static void
814 move_end (WTree *tree)
816 tree_move_to_bottom (tree);
817 show_tree (tree);
818 maybe_chdir (tree);
821 static int
822 move_left (WTree *tree)
824 int v;
826 if (tree_navigation_flag){
827 v = tree_move_to_parent (tree);
828 show_tree (tree);
829 maybe_chdir (tree);
830 return v;
832 return 0;
835 static int
836 move_right (WTree *tree)
838 if (tree_navigation_flag){
839 tree_move_to_child (tree);
840 show_tree (tree);
841 maybe_chdir (tree);
842 return 1;
844 return 0;
847 static void
848 move_prevp (WTree *tree)
850 tree_move_backward (tree, tlines (tree) - 1);
851 show_tree (tree);
852 maybe_chdir (tree);
855 static void
856 move_nextp (WTree *tree)
858 tree_move_forward (tree, tlines (tree) - 1);
859 show_tree (tree);
860 maybe_chdir (tree);
863 static void
864 chdir_sel (WTree *tree)
866 if (!tree->is_panel){
867 tree->done = 1;
868 return;
870 change_panel ();
871 if (do_cd (tree->selected_ptr->name, cd_exact)){
872 paint_panel (cpanel);
873 select_item (cpanel);
874 } else {
875 message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
876 tree->selected_ptr->name, unix_error_string (errno));
878 change_panel ();
879 show_tree (tree);
880 return;
883 static void
884 tree_start_search (WTree *tree)
886 int i;
888 if (tree->searching){
890 if (tree->selected_ptr == tree->store->tree_last)
891 tree_move_to_top(tree);
892 else {
893 /* set navigation mode temporarily to 'Static' because in
894 * dynamic navigation mode tree_move_forward will not move
895 * to a lower sublevel if necessary (sequent searches must
896 * start with the directory followed the last found directory)
898 i = tree_navigation_flag;
899 tree_navigation_flag = 0;
900 tree_move_forward (tree, 1);
901 tree_navigation_flag = i;
903 tree_do_search (tree, 0);
905 else {
906 tree->searching = 1;
907 tree->search_buffer[0] = 0;
911 static const key_map tree_keymap [] = {
912 { XCTRL('n'), move_down },
913 { XCTRL('p'), move_up },
914 { KEY_DOWN, move_down },
915 { KEY_UP, move_up },
916 { '\n', chdir_sel },
917 { KEY_ENTER, chdir_sel },
918 { KEY_HOME, move_home },
919 { KEY_C1, move_end },
920 { KEY_END, move_end },
921 { KEY_A1, move_home },
922 { KEY_NPAGE, move_nextp },
923 { KEY_PPAGE, move_prevp },
924 { XCTRL('v'), move_nextp },
925 { ALT('v'), move_prevp },
926 { XCTRL('p'), move_up },
927 { XCTRL('p'), move_down },
928 { XCTRL('s'), tree_start_search },
929 { ALT('s'), tree_start_search },
930 { XCTRL('r'), tree_rescan_cmd },
931 { KEY_DC, tree_rmdir_cmd },
932 { 0, 0 }
935 static inline int
936 tree_key (WTree *tree, int key)
938 int i;
940 for (i = 0; tree_keymap [i].key_code; i++){
941 if (key == tree_keymap [i].key_code){
942 if (tree_keymap [i].fn != tree_start_search)
943 tree->searching = 0;
944 (*tree_keymap [i].fn)(tree);
945 show_tree (tree);
946 return 1;
950 /* We do not want to use them if we do not need to */
951 /* Input line may want to take the motion key event */
952 if (key == KEY_LEFT)
953 return move_left (tree);
955 if (key == KEY_RIGHT)
956 return move_right (tree);
958 if (is_abort_char (key)) {
959 if (tree->is_panel) {
960 tree->searching = 0;
961 show_tree (tree);
962 return 1; /* eat abort char */
964 return 0; /* modal tree dialog: let upper layer see the
965 abort character and close the dialog */
968 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
969 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
970 if (tree->searching){
971 tree_do_search (tree, key);
972 show_tree (tree);
973 return 1;
976 if (!command_prompt) {
977 tree_start_search (tree);
978 tree_do_search (tree, key);
979 return 1;
981 return tree->is_panel;
984 return 0;
987 static void
988 tree_frame (Dlg_head *h, WTree *tree)
990 attrset (NORMAL_COLOR);
991 widget_erase ((Widget*) tree);
992 if (tree->is_panel)
993 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
994 tree->widget.cols);
996 if (show_mini_info && tree->is_panel){
997 widget_move (tree, tlines (tree) + 1, 1);
998 hline (ACS_HLINE, tree->widget.cols - 2);
1003 static int
1004 tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
1006 switch (msg){
1007 case WIDGET_DRAW:
1008 tree_frame (h, tree);
1009 show_tree (tree);
1010 return 1;
1012 case WIDGET_KEY:
1013 return tree_key (tree, par);
1015 case WIDGET_FOCUS:
1016 tree->active = 1;
1017 define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
1018 define_label_data (h, (Widget *)tree,
1019 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
1020 define_label_data (h, (Widget *)tree,
1021 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
1022 define_label_data (h, (Widget *)tree,
1023 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
1024 define_label_data (h, (Widget *)tree,
1025 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1026 #if 0
1027 /* FIXME: mkdir is currently defunct */
1028 define_label_data (h, (Widget *)tree,
1029 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1030 #else
1031 define_label (h, (Widget *)tree, 7, "", 0);
1032 #endif
1033 define_label_data (h, (Widget *)tree,
1034 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
1035 set_navig_label (tree);
1036 redraw_labels (h, (Widget *)tree);
1039 /* FIXME: Should find a better way of only displaying the
1040 currently selected item */
1041 show_tree (tree);
1042 return 1;
1044 /* FIXME: Should find a better way of changing the color of the
1045 selected item */
1046 case WIDGET_UNFOCUS:
1047 tree->active = 0;
1048 show_tree (tree);
1049 return 1;
1051 return default_proc (h, msg, par);
1054 WTree *
1055 tree_new (int is_panel, int y, int x, int lines, int cols)
1057 WTree *tree = g_new (WTree, 1);
1059 init_widget (&tree->widget, y, x, lines, cols, tcallback,
1060 (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
1061 tree->is_panel = is_panel;
1062 tree->selected_ptr = 0;
1064 tree->store = tree_store_get ();
1065 tree_store_add_entry_remove_hook (remove_callback, tree);
1066 tree->tree_shown = 0;
1067 tree->search_buffer [0] = 0;
1068 tree->topdiff = tree->widget.lines / 2;
1069 tree->searching = 0;
1070 tree->done = 0;
1071 tree->active = 0;
1073 /* We do not want to keep the cursor */
1074 widget_want_cursor (tree->widget, 0);
1075 load_tree (tree);
1076 return tree;