Corrected a misdeleted row that created a crash on f1-f1 key pressing...
[midnight-commander.git] / src / tree.c
blob148c671504bfc7ba4a2f6f93c39e30ba230a771c
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 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 /* "$Id$" */
68 static tree_entry *back_ptr (tree_entry *ptr, int *count)
70 int i = 0;
72 while (ptr && ptr->prev && i < *count){
73 ptr = ptr->prev;
74 i ++;
76 *count = i;
77 return ptr;
80 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
82 int i = 0;
84 while (ptr && ptr->next && i < *count){
85 ptr = ptr->next;
86 i ++;
88 *count = i;
89 return ptr;
92 #if 0
93 /* Add a directory to the list of directories */
94 static tree_entry *tree_add_entry (WTree *tree, char *name)
96 if (!tree)
97 return 0;
99 return tree_store_add_entry (name);
102 /* Append a directory to the list of directories */
103 static tree_entry *tree_append_entry (WTree *tree, char *name)
105 tree_entry *current, *new;
106 int i, len;
107 int submask = 0;
109 /* We assume the directory is not yet in the list */
111 new = g_new (tree_entry, 1);
112 if (!tree->store->tree_first){
113 /* Empty list */
114 tree->store->tree_first = new;
115 new->prev = NULL;
116 } else {
117 tree->tree_last->next = new;
118 new->prev = tree->tree_last;
120 new->next = NULL;
121 tree->store->tree_last = new;
123 /* Calculate attributes */
124 new->name = g_strdup (name);
125 len = strlen (new->name);
126 new->sublevel = 0;
127 for (i = 0; i < len; i++)
128 if (new->name [i] == PATH_SEP){
129 new->sublevel++;
130 new->subname = new->name + i + 1;
132 submask = 1 << new->sublevel;
133 submask &= (2 << new->sublevel) - 1;
134 new->submask = submask;
135 new->mark = 0;
137 /* Correct the submasks of the previous entries */
138 current = new->prev;
139 while (current && current->sublevel > new->sublevel){
140 current->submask |= 1 << new->sublevel;
141 current = current->prev;
144 /* The entry has now been appended */
145 return new;
147 #endif
149 static void
150 remove_callback (tree_entry *entry, void *data)
152 WTree *tree = data;
154 if (tree->selected_ptr == entry){
155 if (tree->selected_ptr->next)
156 tree->selected_ptr = tree->selected_ptr->next;
157 else
158 tree->selected_ptr = tree->selected_ptr->prev;
162 static void tree_remove_entry (WTree *tree, char *name)
164 tree_store_remove_entry (name);
167 static void tree_destroy (WTree *tree)
169 tree_store_remove_entry_remove_hook (remove_callback);
170 save_tree (tree);
172 if (tree->tree_shown){
173 g_free (tree->tree_shown);
174 tree->tree_shown = 0;
176 tree->selected_ptr = NULL;
179 /* Loads the .mc.tree file */
180 static void load_tree (WTree *tree)
182 tree_store_load ();
184 tree->selected_ptr = tree->store->tree_first;
185 tree_chdir (tree, home_dir);
188 /* Save the .mc.tree file */
189 static void save_tree (WTree *tree)
191 int error;
193 error = tree_store_save ();
195 if (error){
196 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
197 unix_error_string (error));
198 return;
202 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
204 Dlg_head *h = tree->widget.parent;
205 int line;
207 /* Show mini info */
208 if (tree->is_panel){
209 if (!show_mini_info)
210 return;
211 line = tree_lines+2;
212 } else
213 line = tree_lines+1;
215 widget_move (&tree->widget, line, 1);
216 hline (' ', tree_cols);
217 widget_move (&tree->widget, line, 1);
219 if (tree->searching){
220 /* Show search string */
221 attrset (TREE_NORMALC);
222 attrset (FOCUSC);
223 addch (PATH_SEP);
225 addstr (name_trunc (tree->search_buffer, tree_cols-2));
226 addch (' ');
227 attrset (FOCUSC);
228 } else {
229 /* Show full name of selected directory */
230 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
234 static void show_tree (WTree *tree)
236 Dlg_head *h = tree->widget.parent;
237 tree_entry *current;
238 int i, j, topsublevel;
239 int x, y;
240 int tree_lines, tree_cols;
242 /* Initialize */
243 x = y = 0;
244 tree_lines = tlines (tree);
245 tree_cols = tree->widget.cols;
247 attrset (TREE_NORMALC);
248 widget_move ((Widget*)tree, y, x);
249 if (tree->is_panel){
250 tree_cols -= 2;
251 x = y = 1;
254 if (tree->tree_shown)
255 g_free (tree->tree_shown);
256 tree->tree_shown = g_new (tree_entry*, tree_lines);
258 for (i = 0; i < tree_lines; i++)
259 tree->tree_shown [i] = NULL;
260 if (tree->store->tree_first)
261 topsublevel = tree->store->tree_first->sublevel;
262 else
263 topsublevel = 0;
264 if (!tree->selected_ptr){
265 tree->selected_ptr = tree->store->tree_first;
266 tree->topdiff = 0;
268 current = tree->selected_ptr;
270 /* Calculate the directory which is to be shown on the topmost line */
271 if (tree_navigation_flag){
272 i = 0;
273 while (current->prev && i < tree->topdiff){
274 current = current->prev;
275 if (current->sublevel < tree->selected_ptr->sublevel){
276 if (strncmp (current->name, tree->selected_ptr->name,
277 strlen (current->name)) == 0)
278 i++;
279 } else if (current->sublevel == tree->selected_ptr->sublevel){
280 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
281 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
282 i++;
283 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
284 && strlen (tree->selected_ptr->name) > 1){
285 if (strncmp (current->name, tree->selected_ptr->name,
286 strlen (tree->selected_ptr->name)) == 0)
287 i++;
290 tree->topdiff = i;
291 } else
292 current = back_ptr (current, &tree->topdiff);
294 /* Loop for every line */
295 for (i = 0; i < tree_lines; i++){
296 /* Move to the beginning of the line */
297 widget_move (&tree->widget, y+i, x);
299 hline (' ', tree_cols);
300 widget_move (&tree->widget, y+i, x);
302 if (!current)
303 continue;
305 tree->tree_shown [i] = current;
306 if (current->sublevel == topsublevel){
308 /* Top level directory */
309 if (tree->active && current == tree->selected_ptr) {
310 if (!use_colors && !tree->is_panel)
311 attrset (MARKED_COLOR);
312 else
313 attrset (SELECTED_COLOR);
316 /* Show full name */
317 addstr (name_trunc (current->name, tree_cols - 6));
318 } else{
319 /* Sub level directory */
321 acs ();
322 /* Output branch parts */
323 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
324 if (tree_cols - 8 - 3 * j < 9)
325 break;
326 addch (' ');
327 if (current->submask & (1 << (j + topsublevel + 1)))
328 addch (ACS_VLINE);
329 else
330 addch (' ');
331 addch (' ');
333 addch (' '); j++;
334 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
335 addch (ACS_LLCORNER);
336 else
337 addch (ACS_LTEE);
338 addch (ACS_HLINE);
339 noacs ();
341 if (tree->active && current == tree->selected_ptr) {
342 /* Selected directory -> change color */
343 if (!use_colors && !tree->is_panel)
344 attrset (MARKED_COLOR);
345 else
346 attrset (SELECTED_COLOR);
349 /* Show sub-name */
350 addch (' ');
351 addstr (name_trunc (current->subname,
352 tree_cols - 2 - 4 - 3 * j));
354 addch (' ');
356 /* Return to normal color */
357 attrset (TREE_NORMALC);
359 /* Calculate the next value for current */
360 current = current->next;
361 if (tree_navigation_flag){
362 while (current){
363 if (current->sublevel < tree->selected_ptr->sublevel){
364 if (strncmp (current->name, tree->selected_ptr->name,
365 strlen (current->name)) == 0)
366 break;
367 } else if (current->sublevel == tree->selected_ptr->sublevel){
368 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
369 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
370 break;
371 } else if (current->sublevel == tree->selected_ptr->sublevel+1
372 && strlen (tree->selected_ptr->name) > 1){
373 if (strncmp (current->name, tree->selected_ptr->name,
374 strlen (tree->selected_ptr->name)) == 0)
375 break;
377 current = current->next;
381 tree_show_mini_info (tree, tree_lines, tree_cols);
384 static void check_focus (WTree *tree)
386 if (tree->topdiff < 3)
387 tree->topdiff = 3;
388 else if (tree->topdiff >= tlines (tree) - 3)
389 tree->topdiff = tlines (tree) - 3 - 1;
392 static void tree_move_backward (WTree *tree, int i)
394 tree_entry *current;
395 int j = 0;
397 if (tree_navigation_flag){
398 current = tree->selected_ptr;
399 while (j < i && current->prev
400 && current->prev->sublevel >= tree->selected_ptr->sublevel){
401 current = current->prev;
402 if (current->sublevel == tree->selected_ptr->sublevel){
403 tree->selected_ptr = current;
404 j ++;
407 i = j;
408 } else
409 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
410 tree->topdiff -= i;
411 check_focus (tree);
414 static void tree_move_forward (WTree *tree, int i)
416 tree_entry *current;
417 int j = 0;
419 if (tree_navigation_flag){
420 current = tree->selected_ptr;
421 while (j < i && current->next
422 && current->next->sublevel >= tree->selected_ptr->sublevel){
423 current = current->next;
424 if (current->sublevel == tree->selected_ptr->sublevel){
425 tree->selected_ptr = current;
426 j ++;
429 i = j;
430 } else
431 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
432 tree->topdiff += i;
433 check_focus (tree);
436 static void tree_move_to_child (WTree *tree)
438 tree_entry *current;
440 /* Do we have a starting point? */
441 if (!tree->selected_ptr)
442 return;
443 /* Take the next entry */
444 current = tree->selected_ptr->next;
445 /* Is it the child of the selected entry */
446 if (current && current->sublevel > tree->selected_ptr->sublevel){
447 /* Yes -> select this entry */
448 tree->selected_ptr = current;
449 tree->topdiff++;
450 check_focus (tree);
451 } else {
452 /* No -> rescan and try again */
453 tree_rescan_cmd (tree);
454 current = tree->selected_ptr->next;
455 if (current && current->sublevel > tree->selected_ptr->sublevel){
456 tree->selected_ptr = current;
457 tree->topdiff++;
458 check_focus (tree);
463 static int tree_move_to_parent (WTree *tree)
465 tree_entry *current;
466 tree_entry *old;
468 if (!tree->selected_ptr)
469 return 0;
470 old = tree->selected_ptr;
471 current = tree->selected_ptr->prev;
472 while (current && current->sublevel >= tree->selected_ptr->sublevel){
473 current = current->prev;
474 tree->topdiff--;
476 if (!current)
477 current = tree->store->tree_first;
478 tree->selected_ptr = current;
479 check_focus (tree);
480 return tree->selected_ptr != old;
483 static void tree_move_to_top (WTree *tree)
485 tree->selected_ptr = tree->store->tree_first;
486 tree->topdiff = 0;
489 static void tree_move_to_bottom (WTree *tree)
491 tree->selected_ptr = tree->store->tree_last;
492 tree->topdiff = tlines (tree) - 3 - 1;
495 void tree_chdir (WTree *tree, char *dir)
497 tree_entry *current;
499 current = tree_store_whereis (dir);
500 if (current){
501 tree->selected_ptr = current;
502 check_focus (tree);
506 void
507 sync_tree (char *path)
509 tree_chdir (the_tree, path);
512 /* Handle mouse click */
513 static void tree_event (WTree *tree, int y)
515 if (tree->tree_shown [y]){
516 tree->selected_ptr = tree->tree_shown [y];
517 tree->topdiff = y;
519 show_tree (tree);
522 static void chdir_sel (WTree *tree);
524 static void maybe_chdir (WTree *tree)
526 if (!(xtree_mode && tree->is_panel))
527 return;
528 if (is_idle ())
529 chdir_sel (tree);
532 /* Mouse callback */
533 static int event_callback (Gpm_Event *event, WTree *tree)
535 if (!(event->type & GPM_UP))
536 return MOU_ENDLOOP;
538 if (tree->is_panel)
539 event->y--;
541 event->y--;
543 if (!tree->active)
544 change_panel ();
546 if (event->y < 0){
547 tree_move_backward (tree, tlines (tree) - 1);
548 show_tree (tree);
550 else if (event->y >= tlines (tree)){
551 tree_move_forward (tree, tlines (tree) - 1);
552 show_tree (tree);
553 } else {
554 tree_event (tree, event->y);
555 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
556 chdir_sel (tree);
559 return MOU_ENDLOOP;
562 /* Search tree for text */
563 static int search_tree (WTree *tree, char *text)
565 tree_entry *current;
566 int len;
567 int wrapped = 0;
568 int found = 0;
570 len = strlen (text);
571 current = tree->selected_ptr;
572 found = 0;
573 while (!wrapped || current != tree->selected_ptr){
574 if (strncmp (current->subname, text, len) == 0){
575 tree->selected_ptr = current;
576 found = 1;
577 break;
579 current = current->next;
580 if (!current){
581 current = tree->store->tree_first;
582 wrapped = 1;
584 tree->topdiff++;
586 check_focus (tree);
587 return found;
590 static void tree_do_search (WTree *tree, int key)
592 int l;
594 l = strlen (tree->search_buffer);
595 if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
596 tree->search_buffer [--l] = 0;
597 else {
598 if (key && l < sizeof (tree->search_buffer)){
599 tree->search_buffer [l] = key;
600 tree->search_buffer [l+1] = 0;
601 l++;
605 if (!search_tree (tree, tree->search_buffer))
606 tree->search_buffer [--l] = 0;
608 show_tree (tree);
609 maybe_chdir (tree);
612 static void tree_rescan_cmd (WTree *tree)
614 char old_dir [MC_MAXPATHLEN];
616 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
617 mc_chdir (tree->selected_ptr->name))
618 return;
620 tree_store_rescan (tree->selected_ptr->name);
621 mc_chdir (old_dir);
624 static int tree_forget_cmd (WTree *tree)
626 if (tree->selected_ptr)
627 tree_remove_entry (tree, tree->selected_ptr->name);
628 return 1;
631 static void tree_copy (WTree *tree, char *default_dest)
633 char *dest;
634 off_t count = 0;
635 double bytes = 0;
636 FileOpContext *ctx;
638 if (!tree->selected_ptr)
639 return;
640 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
641 name_trunc (tree->selected_ptr->name, 50));
642 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
644 if (!dest)
645 return;
647 if (!*dest){
648 g_free (dest);
649 return;
652 ctx = file_op_context_new ();
653 file_op_context_create_ui (ctx, OP_COPY, FALSE);
654 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
655 file_op_context_destroy (ctx);
657 g_free (dest);
660 static void tree_help_cmd (void)
662 interactive_display (NULL, "[Directory Tree]");
665 static int tree_copy_cmd (WTree *tree)
667 tree_copy (tree, "");
668 return 1;
671 static void tree_move (WTree *tree, char *default_dest)
673 char *dest;
674 struct stat buf;
675 double bytes = 0;
676 off_t count = 0;
677 FileOpContext *ctx;
679 if (!tree->selected_ptr)
680 return;
681 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
682 name_trunc (tree->selected_ptr->name, 50));
683 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
684 if (!dest)
685 return;
686 if (!*dest){
687 g_free (dest);
688 return;
690 if (stat (dest, &buf)){
691 message (1, MSG_ERROR, _(" Cannot stat the destination \n %s "),
692 unix_error_string (errno));
693 g_free (dest);
694 return;
696 if (!S_ISDIR (buf.st_mode)){
697 message (1, MSG_ERROR, _(" The destination isn't a directory "));
698 g_free (dest);
699 return;
702 ctx = file_op_context_new ();
703 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
704 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
705 file_op_context_destroy (ctx);
707 g_free (dest);
710 static int
711 tree_move_cmd (WTree *tree)
713 tree_move (tree, "");
714 return 1;
717 #if 0
718 static int
719 tree_mkdir_cmd (WTree *tree)
721 char old_dir [MC_MAXPATHLEN];
723 if (!tree->selected_ptr)
724 return 0;
725 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
726 return 0;
727 if (chdir (tree->selected_ptr->name))
728 return 0;
729 /* FIXME
730 mkdir_cmd (tree);
732 tree_rescan_cmd (tree);
733 chdir (old_dir);
734 return 1;
736 #endif
738 static void
739 tree_rmdir_cmd (WTree *tree)
741 char old_dir [MC_MAXPATHLEN];
742 off_t count = 0;
743 double bytes = 0;
744 FileOpContext *ctx;
746 if (tree->selected_ptr){
747 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
748 return;
749 if (mc_chdir (PATH_SEP_STR))
750 return;
751 if (confirm_delete){
752 char *buf;
753 int result;
755 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
756 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
757 g_free (buf);
758 if (result != 0){
759 return;
763 ctx = file_op_context_new ();
764 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
765 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
766 tree_forget_cmd (tree);
767 file_op_context_destroy (ctx);
768 mc_chdir (old_dir);
769 return;
770 } else
771 return;
774 static void set_navig_label (WTree *tree);
776 static void
777 tree_toggle_navig (WTree *tree)
779 tree_navigation_flag = 1 - tree_navigation_flag;
780 set_navig_label (tree);
783 static void
784 set_navig_label (WTree *tree)
786 define_label_data (tree->widget.parent, (Widget *) tree,
787 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
788 (buttonbarfn) tree_toggle_navig, tree);
791 static void
792 move_down (WTree *tree)
794 tree_move_forward (tree, 1);
795 show_tree (tree);
796 maybe_chdir (tree);
799 static void
800 move_up (WTree *tree)
802 tree_move_backward (tree, 1);
803 show_tree (tree);
804 maybe_chdir (tree);
807 static void
808 move_home (WTree *tree)
810 tree_move_to_top (tree);
811 show_tree (tree);
812 maybe_chdir (tree);
815 static void
816 move_end (WTree *tree)
818 tree_move_to_bottom (tree);
819 show_tree (tree);
820 maybe_chdir (tree);
823 static int
824 move_left (WTree *tree)
826 int v;
828 if (tree_navigation_flag){
829 v = tree_move_to_parent (tree);
830 show_tree (tree);
831 maybe_chdir (tree);
832 return v;
834 return 0;
837 static int
838 move_right (WTree *tree)
840 if (tree_navigation_flag){
841 tree_move_to_child (tree);
842 show_tree (tree);
843 maybe_chdir (tree);
844 return 1;
846 return 0;
849 static void
850 move_prevp (WTree *tree)
852 tree_move_backward (tree, tlines (tree) - 1);
853 show_tree (tree);
854 maybe_chdir (tree);
857 static void
858 move_nextp (WTree *tree)
860 tree_move_forward (tree, tlines (tree) - 1);
861 show_tree (tree);
862 maybe_chdir (tree);
865 static void
866 chdir_sel (WTree *tree)
868 if (!tree->is_panel){
869 tree->done = 1;
870 return;
872 change_panel ();
873 if (do_cd (tree->selected_ptr->name, cd_exact)){
874 paint_panel (cpanel);
875 select_item (cpanel);
876 } else {
877 message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
878 tree->selected_ptr->name, unix_error_string (errno));
880 change_panel ();
881 show_tree (tree);
882 return;
885 static void
886 tree_start_search (WTree *tree)
888 int i;
890 if (tree->searching){
892 if (tree->selected_ptr == tree->store->tree_last)
893 tree_move_to_top(tree);
894 else {
895 /* set navigation mode temporarily to 'Static' because in
896 * dynamic navigation mode tree_move_forward will not move
897 * to a lower sublevel if necessary (sequent searches must
898 * start with the directory followed the last found directory)
900 i = tree_navigation_flag;
901 tree_navigation_flag = 0;
902 tree_move_forward (tree, 1);
903 tree_navigation_flag = i;
905 tree_do_search (tree, 0);
907 else {
908 tree->searching = 1;
909 tree->search_buffer[0] = 0;
913 static const key_map tree_keymap [] = {
914 { XCTRL('n'), move_down },
915 { XCTRL('p'), move_up },
916 { KEY_DOWN, move_down },
917 { KEY_UP, move_up },
918 { '\n', chdir_sel },
919 { KEY_ENTER, chdir_sel },
920 { KEY_HOME, move_home },
921 { KEY_C1, move_end },
922 { KEY_END, move_end },
923 { KEY_A1, move_home },
924 { KEY_NPAGE, move_nextp },
925 { KEY_PPAGE, move_prevp },
926 { XCTRL('v'), move_nextp },
927 { ALT('v'), move_prevp },
928 { XCTRL('p'), move_up },
929 { XCTRL('p'), move_down },
930 { XCTRL('s'), tree_start_search },
931 { ALT('s'), tree_start_search },
932 { XCTRL('r'), tree_rescan_cmd },
933 { KEY_DC, tree_rmdir_cmd },
934 { 0, 0 }
937 static inline int
938 tree_key (WTree *tree, int key)
940 int i;
942 for (i = 0; tree_keymap [i].key_code; i++){
943 if (key == tree_keymap [i].key_code){
944 if (tree_keymap [i].fn != tree_start_search)
945 tree->searching = 0;
946 (*tree_keymap [i].fn)(tree);
947 show_tree (tree);
948 return 1;
952 /* We do not want to use them if we do not need to */
953 /* Input line may want to take the motion key event */
954 if (key == KEY_LEFT)
955 return move_left (tree);
957 if (key == KEY_RIGHT)
958 return move_right (tree);
960 if (is_abort_char (key)) {
961 if (tree->is_panel) {
962 tree->searching = 0;
963 show_tree (tree);
964 return 1; /* eat abort char */
966 return 0; /* modal tree dialog: let upper layer see the
967 abort character and close the dialog */
970 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
971 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
972 if (tree->searching){
973 tree_do_search (tree, key);
974 show_tree (tree);
975 return 1;
978 if (!command_prompt) {
979 tree_start_search (tree);
980 tree_do_search (tree, key);
981 return 1;
983 return tree->is_panel;
986 return 0;
989 static void
990 tree_frame (Dlg_head *h, WTree *tree)
992 attrset (NORMAL_COLOR);
993 widget_erase ((Widget*) tree);
994 if (tree->is_panel)
995 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
996 tree->widget.cols);
998 if (show_mini_info && tree->is_panel){
999 widget_move (tree, tlines (tree) + 1, 1);
1000 hline (ACS_HLINE, tree->widget.cols - 2);
1005 static int
1006 tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
1008 switch (msg){
1009 case WIDGET_DRAW:
1010 tree_frame (h, tree);
1011 show_tree (tree);
1012 return 1;
1014 case WIDGET_KEY:
1015 return tree_key (tree, par);
1017 case WIDGET_FOCUS:
1018 tree->active = 1;
1019 define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
1020 define_label_data (h, (Widget *)tree,
1021 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
1022 define_label_data (h, (Widget *)tree,
1023 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
1024 define_label_data (h, (Widget *)tree,
1025 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
1026 define_label_data (h, (Widget *)tree,
1027 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1028 #if 0
1029 /* FIXME: mkdir is currently defunct */
1030 define_label_data (h, (Widget *)tree,
1031 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1032 #else
1033 define_label (h, (Widget *)tree, 7, "", 0);
1034 #endif
1035 define_label_data (h, (Widget *)tree,
1036 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
1037 set_navig_label (tree);
1038 redraw_labels (h, (Widget *)tree);
1041 /* FIXME: Should find a better way of only displaying the
1042 currently selected item */
1043 show_tree (tree);
1044 return 1;
1046 /* FIXME: Should find a better way of changing the color of the
1047 selected item */
1048 case WIDGET_UNFOCUS:
1049 tree->active = 0;
1050 show_tree (tree);
1051 return 1;
1053 return default_proc (h, msg, par);
1056 WTree *
1057 tree_new (int is_panel, int y, int x, int lines, int cols)
1059 WTree *tree = g_new (WTree, 1);
1061 init_widget (&tree->widget, y, x, lines, cols, tcallback,
1062 (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
1063 tree->is_panel = is_panel;
1064 tree->selected_ptr = 0;
1066 tree->store = tree_store_get ();
1067 tree_store_add_entry_remove_hook (remove_callback, tree);
1068 tree->tree_shown = 0;
1069 tree->search_buffer [0] = 0;
1070 tree->topdiff = tree->widget.lines / 2;
1071 tree->searching = 0;
1072 tree->done = 0;
1073 tree->active = 0;
1075 /* We do not want to keep the cursor */
1076 widget_want_cursor (tree->widget, 0);
1077 load_tree (tree);
1078 return tree;