*** empty log message ***
[midnight-commander.git] / src / tree.c
blob8bfbabffcc1da08e173fa85ea824acc111b7e43f
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 #define TREE_NORMALC HOT_FOCUSC
56 /* Specifies the display mode: 1d or 2d */
57 int tree_navigation_flag;
59 /* Forwards */
60 static void save_tree (WTree *tree);
61 static void tree_rescan_cmd (WTree *tree);
62 static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
63 #define tcallback (callback_fn) tree_callback
65 /* "$Id$" */
67 static tree_entry *back_ptr (tree_entry *ptr, int *count)
69 int i = 0;
71 while (ptr && ptr->prev && i < *count){
72 ptr = ptr->prev;
73 i ++;
75 *count = i;
76 return ptr;
79 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
81 int i = 0;
83 while (ptr && ptr->next && i < *count){
84 ptr = ptr->next;
85 i ++;
87 *count = i;
88 return ptr;
91 #if 0
92 /* Add a directory to the list of directories */
93 static tree_entry *tree_add_entry (WTree *tree, char *name)
95 if (!tree)
96 return 0;
98 return tree_store_add_entry (name);
101 /* Append a directory to the list of directories */
102 static tree_entry *tree_append_entry (WTree *tree, char *name)
104 tree_entry *current, *new;
105 int i, len;
106 int submask = 0;
108 /* We assume the directory is not yet in the list */
110 new = g_new (tree_entry, 1);
111 if (!tree->store->tree_first){
112 /* Empty list */
113 tree->store->tree_first = new;
114 new->prev = NULL;
115 } else {
116 tree->tree_last->next = new;
117 new->prev = tree->tree_last;
119 new->next = NULL;
120 tree->store->tree_last = new;
122 /* Calculate attributes */
123 new->name = g_strdup (name);
124 len = strlen (new->name);
125 new->sublevel = 0;
126 for (i = 0; i < len; i++)
127 if (new->name [i] == PATH_SEP){
128 new->sublevel++;
129 new->subname = new->name + i + 1;
131 submask = 1 << new->sublevel;
132 submask &= (2 << new->sublevel) - 1;
133 new->submask = submask;
134 new->mark = 0;
136 /* Correct the submasks of the previous entries */
137 current = new->prev;
138 while (current && current->sublevel > new->sublevel){
139 current->submask |= 1 << new->sublevel;
140 current = current->prev;
143 /* The entry has now been appended */
144 return new;
146 #endif
148 static void
149 remove_callback (tree_entry *entry, void *data)
151 WTree *tree = data;
153 if (tree->selected_ptr == entry){
154 if (tree->selected_ptr->next)
155 tree->selected_ptr = tree->selected_ptr->next;
156 else
157 tree->selected_ptr = tree->selected_ptr->prev;
161 static void tree_remove_entry (WTree *tree, char *name)
163 tree_store_remove_entry (name);
166 static void tree_destroy (WTree *tree)
168 tree_store_remove_entry_remove_hook (remove_callback);
169 save_tree (tree);
171 if (tree->tree_shown){
172 g_free (tree->tree_shown);
173 tree->tree_shown = 0;
175 tree->selected_ptr = NULL;
178 /* Loads the .mc.tree file */
179 static void load_tree (WTree *tree)
181 tree_store_load ();
183 tree->selected_ptr = tree->store->tree_first;
184 tree_chdir (tree, home_dir);
187 /* Save the .mc.tree file */
188 static void save_tree (WTree *tree)
190 int error;
192 error = tree_store_save ();
194 if (error){
195 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
196 unix_error_string (error));
197 return;
201 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
203 Dlg_head *h = tree->widget.parent;
204 int line;
206 /* Show mini info */
207 if (tree->is_panel){
208 if (!show_mini_info)
209 return;
210 line = tree_lines+2;
211 } else
212 line = tree_lines+1;
214 widget_move (&tree->widget, line, 1);
215 hline (' ', tree_cols);
216 widget_move (&tree->widget, line, 1);
218 if (tree->searching){
219 /* Show search string */
220 attrset (TREE_NORMALC);
221 attrset (FOCUSC);
222 addch (PATH_SEP);
224 addstr (name_trunc (tree->search_buffer, tree_cols-2));
225 addch (' ');
226 attrset (FOCUSC);
227 } else {
228 /* Show full name of selected directory */
229 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
233 static void show_tree (WTree *tree)
235 Dlg_head *h = tree->widget.parent;
236 tree_entry *current;
237 int i, j, topsublevel;
238 int x, y;
239 int tree_lines, tree_cols;
241 /* Initialize */
242 x = y = 0;
243 tree_lines = tlines (tree);
244 tree_cols = tree->widget.cols;
246 attrset (TREE_NORMALC);
247 widget_move ((Widget*)tree, y, x);
248 if (tree->is_panel){
249 tree_cols -= 2;
250 x = y = 1;
253 if (tree->tree_shown)
254 g_free (tree->tree_shown);
255 tree->tree_shown = g_new (tree_entry*, tree_lines);
257 for (i = 0; i < tree_lines; i++)
258 tree->tree_shown [i] = NULL;
259 if (tree->store->tree_first)
260 topsublevel = tree->store->tree_first->sublevel;
261 else
262 topsublevel = 0;
263 if (!tree->selected_ptr){
264 tree->selected_ptr = tree->store->tree_first;
265 tree->topdiff = 0;
267 current = tree->selected_ptr;
269 /* Calculate the directory which is to be shown on the topmost line */
270 if (tree_navigation_flag){
271 i = 0;
272 while (current->prev && i < tree->topdiff){
273 current = current->prev;
274 if (current->sublevel < tree->selected_ptr->sublevel){
275 if (strncmp (current->name, tree->selected_ptr->name,
276 strlen (current->name)) == 0)
277 i++;
278 } else if (current->sublevel == tree->selected_ptr->sublevel){
279 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
280 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
281 i++;
282 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
283 && strlen (tree->selected_ptr->name) > 1){
284 if (strncmp (current->name, tree->selected_ptr->name,
285 strlen (tree->selected_ptr->name)) == 0)
286 i++;
289 tree->topdiff = i;
290 } else
291 current = back_ptr (current, &tree->topdiff);
293 /* Loop for every line */
294 for (i = 0; i < tree_lines; i++){
295 /* Move to the beginning of the line */
296 widget_move (&tree->widget, y+i, x);
298 hline (' ', tree_cols);
299 widget_move (&tree->widget, y+i, x);
301 if (!current)
302 continue;
304 tree->tree_shown [i] = current;
305 if (current->sublevel == topsublevel){
307 /* Top level directory */
308 if (tree->active && current == tree->selected_ptr) {
309 if (!use_colors && !tree->is_panel)
310 attrset (MARKED_COLOR);
311 else
312 attrset (SELECTED_COLOR);
315 /* Show full name */
316 addstr (name_trunc (current->name, tree_cols - 6));
317 } else{
318 /* Sub level directory */
320 acs ();
321 /* Output branch parts */
322 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
323 if (tree_cols - 8 - 3 * j < 9)
324 break;
325 addch (' ');
326 if (current->submask & (1 << (j + topsublevel + 1)))
327 addch (ACS_VLINE);
328 else
329 addch (' ');
330 addch (' ');
332 addch (' '); j++;
333 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
334 addch (ACS_LLCORNER);
335 else
336 addch (ACS_LTEE);
337 addch (ACS_HLINE);
338 noacs ();
340 if (tree->active && current == tree->selected_ptr) {
341 /* Selected directory -> change color */
342 if (!use_colors && !tree->is_panel)
343 attrset (MARKED_COLOR);
344 else
345 attrset (SELECTED_COLOR);
348 /* Show sub-name */
349 addch (' ');
350 addstr (name_trunc (current->subname,
351 tree_cols - 2 - 4 - 3 * j));
353 addch (' ');
355 /* Return to normal color */
356 attrset (TREE_NORMALC);
358 /* Calculate the next value for current */
359 current = current->next;
360 if (tree_navigation_flag){
361 while (current){
362 if (current->sublevel < tree->selected_ptr->sublevel){
363 if (strncmp (current->name, tree->selected_ptr->name,
364 strlen (current->name)) == 0)
365 break;
366 } else if (current->sublevel == tree->selected_ptr->sublevel){
367 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
368 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
369 break;
370 } else if (current->sublevel == tree->selected_ptr->sublevel+1
371 && strlen (tree->selected_ptr->name) > 1){
372 if (strncmp (current->name, tree->selected_ptr->name,
373 strlen (tree->selected_ptr->name)) == 0)
374 break;
376 current = current->next;
380 tree_show_mini_info (tree, tree_lines, tree_cols);
383 static void check_focus (WTree *tree)
385 if (tree->topdiff < 3)
386 tree->topdiff = 3;
387 else if (tree->topdiff >= tlines (tree) - 3)
388 tree->topdiff = tlines (tree) - 3 - 1;
391 static void tree_move_backward (WTree *tree, int i)
393 tree_entry *current;
394 int j = 0;
396 if (tree_navigation_flag){
397 current = tree->selected_ptr;
398 while (j < i && current->prev
399 && current->prev->sublevel >= tree->selected_ptr->sublevel){
400 current = current->prev;
401 if (current->sublevel == tree->selected_ptr->sublevel){
402 tree->selected_ptr = current;
403 j ++;
406 i = j;
407 } else
408 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
409 tree->topdiff -= i;
410 check_focus (tree);
413 static void tree_move_forward (WTree *tree, int i)
415 tree_entry *current;
416 int j = 0;
418 if (tree_navigation_flag){
419 current = tree->selected_ptr;
420 while (j < i && current->next
421 && current->next->sublevel >= tree->selected_ptr->sublevel){
422 current = current->next;
423 if (current->sublevel == tree->selected_ptr->sublevel){
424 tree->selected_ptr = current;
425 j ++;
428 i = j;
429 } else
430 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
431 tree->topdiff += i;
432 check_focus (tree);
435 static void tree_move_to_child (WTree *tree)
437 tree_entry *current;
439 /* Do we have a starting point? */
440 if (!tree->selected_ptr)
441 return;
442 /* Take the next entry */
443 current = tree->selected_ptr->next;
444 /* Is it the child of the selected entry */
445 if (current && current->sublevel > tree->selected_ptr->sublevel){
446 /* Yes -> select this entry */
447 tree->selected_ptr = current;
448 tree->topdiff++;
449 check_focus (tree);
450 } else {
451 /* No -> rescan and try again */
452 tree_rescan_cmd (tree);
453 current = tree->selected_ptr->next;
454 if (current && current->sublevel > tree->selected_ptr->sublevel){
455 tree->selected_ptr = current;
456 tree->topdiff++;
457 check_focus (tree);
462 static int tree_move_to_parent (WTree *tree)
464 tree_entry *current;
465 tree_entry *old;
467 if (!tree->selected_ptr)
468 return 0;
469 old = tree->selected_ptr;
470 current = tree->selected_ptr->prev;
471 while (current && current->sublevel >= tree->selected_ptr->sublevel){
472 current = current->prev;
473 tree->topdiff--;
475 if (!current)
476 current = tree->store->tree_first;
477 tree->selected_ptr = current;
478 check_focus (tree);
479 return tree->selected_ptr != old;
482 static void tree_move_to_top (WTree *tree)
484 tree->selected_ptr = tree->store->tree_first;
485 tree->topdiff = 0;
488 static void tree_move_to_bottom (WTree *tree)
490 tree->selected_ptr = tree->store->tree_last;
491 tree->topdiff = tlines (tree) - 3 - 1;
494 void tree_chdir (WTree *tree, char *dir)
496 tree_entry *current;
498 current = tree_store_whereis (dir);
499 if (current){
500 tree->selected_ptr = current;
501 check_focus (tree);
505 void
506 sync_tree (char *path)
508 tree_chdir (the_tree, path);
511 /* Handle mouse click */
512 static void tree_event (WTree *tree, int y)
514 if (tree->tree_shown [y]){
515 tree->selected_ptr = tree->tree_shown [y];
516 tree->topdiff = y;
518 show_tree (tree);
521 static void chdir_sel (WTree *tree);
523 static void maybe_chdir (WTree *tree)
525 if (!(xtree_mode && tree->is_panel))
526 return;
527 if (is_idle ())
528 chdir_sel (tree);
531 /* Mouse callback */
532 static int event_callback (Gpm_Event *event, WTree *tree)
534 if (!(event->type & GPM_UP))
535 return MOU_ENDLOOP;
537 if (tree->is_panel)
538 event->y--;
540 event->y--;
542 if (!tree->active)
543 change_panel ();
545 if (event->y < 0){
546 tree_move_backward (tree, tlines (tree) - 1);
547 show_tree (tree);
549 else if (event->y >= tlines (tree)){
550 tree_move_forward (tree, tlines (tree) - 1);
551 show_tree (tree);
552 } else {
553 tree_event (tree, event->y);
554 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
555 chdir_sel (tree);
558 return MOU_ENDLOOP;
561 /* Search tree for text */
562 static int search_tree (WTree *tree, char *text)
564 tree_entry *current;
565 int len;
566 int wrapped = 0;
567 int found = 0;
569 len = strlen (text);
570 current = tree->selected_ptr;
571 found = 0;
572 while (!wrapped || current != tree->selected_ptr){
573 if (strncmp (current->subname, text, len) == 0){
574 tree->selected_ptr = current;
575 found = 1;
576 break;
578 current = current->next;
579 if (!current){
580 current = tree->store->tree_first;
581 wrapped = 1;
583 tree->topdiff++;
585 check_focus (tree);
586 return found;
589 static void tree_do_search (WTree *tree, int key)
591 int l;
593 l = strlen (tree->search_buffer);
594 if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
595 tree->search_buffer [--l] = 0;
596 else {
597 if (key && l < sizeof (tree->search_buffer)){
598 tree->search_buffer [l] = key;
599 tree->search_buffer [l+1] = 0;
600 l++;
604 if (!search_tree (tree, tree->search_buffer))
605 tree->search_buffer [--l] = 0;
607 show_tree (tree);
608 maybe_chdir (tree);
611 static void tree_rescan_cmd (WTree *tree)
613 char old_dir [MC_MAXPATHLEN];
615 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
616 mc_chdir (tree->selected_ptr->name))
617 return;
619 tree_store_rescan (tree->selected_ptr->name);
620 mc_chdir (old_dir);
623 static int tree_forget_cmd (WTree *tree)
625 if (tree->selected_ptr)
626 tree_remove_entry (tree, tree->selected_ptr->name);
627 return 1;
630 static void tree_copy (WTree *tree, char *default_dest)
632 char *dest;
633 off_t count = 0;
634 double bytes = 0;
635 FileOpContext *ctx;
637 if (!tree->selected_ptr)
638 return;
639 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
640 name_trunc (tree->selected_ptr->name, 50));
641 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
643 if (!dest)
644 return;
646 if (!*dest){
647 g_free (dest);
648 return;
651 ctx = file_op_context_new ();
652 file_op_context_create_ui (ctx, OP_COPY, FALSE);
653 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
654 file_op_context_destroy (ctx);
656 g_free (dest);
659 static void tree_help_cmd (void)
661 interactive_display (NULL, "[Directory Tree]");
664 static int tree_copy_cmd (WTree *tree)
666 tree_copy (tree, "");
667 return 1;
670 static void tree_move (WTree *tree, char *default_dest)
672 char *dest;
673 struct stat buf;
674 double bytes = 0;
675 off_t count = 0;
676 FileOpContext *ctx;
678 if (!tree->selected_ptr)
679 return;
680 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
681 name_trunc (tree->selected_ptr->name, 50));
682 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
683 if (!dest)
684 return;
685 if (!*dest){
686 g_free (dest);
687 return;
689 if (stat (dest, &buf)){
690 message (1, MSG_ERROR, _(" Cannot stat the destination \n %s "),
691 unix_error_string (errno));
692 g_free (dest);
693 return;
695 if (!S_ISDIR (buf.st_mode)){
696 message (1, MSG_ERROR, _(" The destination isn't a directory "));
697 g_free (dest);
698 return;
701 ctx = file_op_context_new ();
702 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
703 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
704 file_op_context_destroy (ctx);
706 g_free (dest);
709 static int
710 tree_move_cmd (WTree *tree)
712 tree_move (tree, "");
713 return 1;
716 #if 0
717 static int
718 tree_mkdir_cmd (WTree *tree)
720 char old_dir [MC_MAXPATHLEN];
722 if (!tree->selected_ptr)
723 return 0;
724 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
725 return 0;
726 if (chdir (tree->selected_ptr->name))
727 return 0;
728 /* FIXME
729 mkdir_cmd (tree);
731 tree_rescan_cmd (tree);
732 chdir (old_dir);
733 return 1;
735 #endif
737 static void
738 tree_rmdir_cmd (WTree *tree)
740 char old_dir [MC_MAXPATHLEN];
741 off_t count = 0;
742 double bytes = 0;
743 FileOpContext *ctx;
745 if (tree->selected_ptr){
746 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
747 return;
748 if (mc_chdir (PATH_SEP_STR))
749 return;
750 if (confirm_delete){
751 char *buf;
752 int result;
754 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
755 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
756 g_free (buf);
757 if (result != 0){
758 return;
762 ctx = file_op_context_new ();
763 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
764 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
765 tree_forget_cmd (tree);
766 file_op_context_destroy (ctx);
767 mc_chdir (old_dir);
768 return;
769 } else
770 return;
773 static void set_navig_label (WTree *tree);
775 static void
776 tree_toggle_navig (WTree *tree)
778 tree_navigation_flag = 1 - tree_navigation_flag;
779 set_navig_label (tree);
782 static void
783 set_navig_label (WTree *tree)
785 define_label_data (tree->widget.parent, (Widget *) tree,
786 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
787 (buttonbarfn) tree_toggle_navig, tree);
790 static void
791 move_down (WTree *tree)
793 tree_move_forward (tree, 1);
794 show_tree (tree);
795 maybe_chdir (tree);
798 static void
799 move_up (WTree *tree)
801 tree_move_backward (tree, 1);
802 show_tree (tree);
803 maybe_chdir (tree);
806 static void
807 move_home (WTree *tree)
809 tree_move_to_top (tree);
810 show_tree (tree);
811 maybe_chdir (tree);
814 static void
815 move_end (WTree *tree)
817 tree_move_to_bottom (tree);
818 show_tree (tree);
819 maybe_chdir (tree);
822 static int
823 move_left (WTree *tree)
825 int v;
827 if (tree_navigation_flag){
828 v = tree_move_to_parent (tree);
829 show_tree (tree);
830 maybe_chdir (tree);
831 return v;
833 return 0;
836 static int
837 move_right (WTree *tree)
839 if (tree_navigation_flag){
840 tree_move_to_child (tree);
841 show_tree (tree);
842 maybe_chdir (tree);
843 return 1;
845 return 0;
848 static void
849 move_prevp (WTree *tree)
851 tree_move_backward (tree, tlines (tree) - 1);
852 show_tree (tree);
853 maybe_chdir (tree);
856 static void
857 move_nextp (WTree *tree)
859 tree_move_forward (tree, tlines (tree) - 1);
860 show_tree (tree);
861 maybe_chdir (tree);
864 static void
865 chdir_sel (WTree *tree)
867 if (!tree->is_panel){
868 tree->done = 1;
869 return;
871 change_panel ();
872 if (do_cd (tree->selected_ptr->name, cd_exact)){
873 paint_panel (cpanel);
874 select_item (cpanel);
875 } else {
876 message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
877 tree->selected_ptr->name, unix_error_string (errno));
879 change_panel ();
880 show_tree (tree);
881 return;
884 static void
885 tree_start_search (WTree *tree)
887 int i;
889 if (tree->searching){
891 if (tree->selected_ptr == tree->store->tree_last)
892 tree_move_to_top(tree);
893 else {
894 /* set navigation mode temporarily to 'Static' because in
895 * dynamic navigation mode tree_move_forward will not move
896 * to a lower sublevel if necessary (sequent searches must
897 * start with the directory followed the last found directory)
899 i = tree_navigation_flag;
900 tree_navigation_flag = 0;
901 tree_move_forward (tree, 1);
902 tree_navigation_flag = i;
904 tree_do_search (tree, 0);
906 else {
907 tree->searching = 1;
908 tree->search_buffer[0] = 0;
912 static const key_map tree_keymap [] = {
913 { XCTRL('n'), move_down },
914 { XCTRL('p'), move_up },
915 { KEY_DOWN, move_down },
916 { KEY_UP, move_up },
917 { '\n', chdir_sel },
918 { KEY_ENTER, chdir_sel },
919 { KEY_HOME, move_home },
920 { KEY_C1, move_end },
921 { KEY_END, move_end },
922 { KEY_A1, move_home },
923 { KEY_NPAGE, move_nextp },
924 { KEY_PPAGE, move_prevp },
925 { XCTRL('v'), move_nextp },
926 { ALT('v'), move_prevp },
927 { XCTRL('p'), move_up },
928 { XCTRL('p'), move_down },
929 { XCTRL('s'), tree_start_search },
930 { ALT('s'), tree_start_search },
931 { XCTRL('r'), tree_rescan_cmd },
932 { KEY_DC, tree_rmdir_cmd },
933 { 0, 0 }
936 static inline int
937 tree_key (WTree *tree, int key)
939 int i;
941 for (i = 0; tree_keymap [i].key_code; i++){
942 if (key == tree_keymap [i].key_code){
943 if (tree_keymap [i].fn != tree_start_search)
944 tree->searching = 0;
945 (*tree_keymap [i].fn)(tree);
946 show_tree (tree);
947 return 1;
951 /* We do not want to use them if we do not need to */
952 /* Input line may want to take the motion key event */
953 if (key == KEY_LEFT)
954 return move_left (tree);
956 if (key == KEY_RIGHT)
957 return move_right (tree);
959 if (is_abort_char (key)) {
960 if (tree->is_panel) {
961 tree->searching = 0;
962 show_tree (tree);
963 return 1; /* eat abort char */
965 return 0; /* modal tree dialog: let upper layer see the
966 abort character and close the dialog */
969 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
970 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
971 if (tree->searching){
972 tree_do_search (tree, key);
973 show_tree (tree);
974 return 1;
977 if (!command_prompt) {
978 tree_start_search (tree);
979 tree_do_search (tree, key);
980 return 1;
982 return tree->is_panel;
985 return 0;
988 static void
989 tree_frame (Dlg_head *h, WTree *tree)
991 attrset (NORMAL_COLOR);
992 widget_erase ((Widget*) tree);
993 if (tree->is_panel)
994 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
995 tree->widget.cols);
997 if (show_mini_info && tree->is_panel){
998 widget_move (tree, tlines (tree) + 1, 1);
999 hline (ACS_HLINE, tree->widget.cols - 2);
1004 static int
1005 tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
1007 switch (msg){
1008 case WIDGET_DRAW:
1009 tree_frame (h, tree);
1010 show_tree (tree);
1011 return 1;
1013 case WIDGET_KEY:
1014 return tree_key (tree, par);
1016 case WIDGET_FOCUS:
1017 tree->active = 1;
1018 define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
1019 define_label_data (h, (Widget *)tree,
1020 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
1021 define_label_data (h, (Widget *)tree,
1022 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
1023 define_label_data (h, (Widget *)tree,
1024 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
1025 define_label_data (h, (Widget *)tree,
1026 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1027 #if 0
1028 /* FIXME: mkdir is currently defunct */
1029 define_label_data (h, (Widget *)tree,
1030 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1031 #else
1032 define_label (h, (Widget *)tree, 7, "", 0);
1033 #endif
1034 define_label_data (h, (Widget *)tree,
1035 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
1036 set_navig_label (tree);
1037 redraw_labels (h, (Widget *)tree);
1040 /* FIXME: Should find a better way of only displaying the
1041 currently selected item */
1042 show_tree (tree);
1043 return 1;
1045 /* FIXME: Should find a better way of changing the color of the
1046 selected item */
1047 case WIDGET_UNFOCUS:
1048 tree->active = 0;
1049 show_tree (tree);
1050 return 1;
1052 return default_proc (h, msg, par);
1055 WTree *
1056 tree_new (int is_panel, int y, int x, int lines, int cols)
1058 WTree *tree = g_new (WTree, 1);
1060 init_widget (&tree->widget, y, x, lines, cols, tcallback,
1061 (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
1062 tree->is_panel = is_panel;
1063 tree->selected_ptr = 0;
1065 tree->store = tree_store_get ();
1066 tree_store_add_entry_remove_hook (remove_callback, tree);
1067 tree->tree_shown = 0;
1068 tree->search_buffer [0] = 0;
1069 tree->topdiff = tree->widget.lines / 2;
1070 tree->searching = 0;
1071 tree->done = 0;
1072 tree->active = 0;
1074 /* We do not want to keep the cursor */
1075 widget_want_cursor (tree->widget, 0);
1076 load_tree (tree);
1077 return tree;