Update base version to 4.6.1.
[midnight-commander.git] / src / tree.c
blobd4c826d27c2344276d6c4088e740d50fbe0ae191
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <string.h>
35 #include "global.h"
36 #include "tty.h"
37 #include "color.h"
38 #include "wtools.h" /* message() */
39 #include "dir.h"
40 #include "dialog.h"
41 #include "widget.h"
42 #include "panel.h"
43 #include "mouse.h"
44 #include "main.h"
45 #include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
46 #include "help.h"
47 #include "key.h" /* For mi_getch() */
48 #include "tree.h"
49 #include "treestore.h"
50 #include "cmd.h"
52 #define tlines(t) (t->is_panel ? t->widget.lines-2 - (show_mini_info ? 2 : 0) : t->widget.lines)
54 extern int command_prompt;
56 /* Use the color of the parent widget for the unselected entries */
57 #define TREE_NORMALC(h) (DLG_NORMALC (h))
59 /* Specifies the display mode: 1d or 2d */
60 static int tree_navigation_flag;
62 struct WTree {
63 Widget widget;
64 struct TreeStore *store;
65 tree_entry *selected_ptr; /* The selected directory */
66 char search_buffer[256]; /* Current search string */
67 tree_entry **tree_shown; /* Entries currently on screen */
68 int is_panel; /* panel or plain widget flag */
69 int active; /* if it's currently selected */
70 int searching; /* Are we on searching mode? */
71 int topdiff; /* The difference between the topmost
72 shown and the selected */
75 /* Forwards */
76 static void save_tree (WTree *tree);
77 static void tree_rescan_cmd (WTree *);
79 static tree_entry *back_ptr (tree_entry *ptr, int *count)
81 int i = 0;
83 while (ptr && ptr->prev && i < *count){
84 ptr = ptr->prev;
85 i ++;
87 *count = i;
88 return ptr;
91 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
93 int i = 0;
95 while (ptr && ptr->next && i < *count){
96 ptr = ptr->next;
97 i ++;
99 *count = i;
100 return ptr;
103 static void
104 remove_callback (tree_entry *entry, void *data)
106 WTree *tree = data;
108 if (tree->selected_ptr == entry){
109 if (tree->selected_ptr->next)
110 tree->selected_ptr = tree->selected_ptr->next;
111 else
112 tree->selected_ptr = tree->selected_ptr->prev;
116 static void tree_remove_entry (WTree *tree, char *name)
118 (void) tree;
119 tree_store_remove_entry (name);
122 static void tree_destroy (WTree *tree)
124 tree_store_remove_entry_remove_hook (remove_callback);
125 save_tree (tree);
127 g_free (tree->tree_shown);
128 tree->tree_shown = 0;
129 tree->selected_ptr = NULL;
132 /* Loads the .mc.tree file */
133 static void load_tree (WTree *tree)
135 tree_store_load ();
137 tree->selected_ptr = tree->store->tree_first;
138 tree_chdir (tree, home_dir);
141 /* Save the .mc.tree file */
142 static void save_tree (WTree *tree)
144 int error;
146 (void) tree;
147 error = tree_store_save ();
149 if (error){
150 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
151 unix_error_string (error));
155 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
157 Dlg_head *h = tree->widget.parent;
158 int line;
160 /* Show mini info */
161 if (tree->is_panel){
162 if (!show_mini_info)
163 return;
164 line = tree_lines+2;
165 } else
166 line = tree_lines+1;
168 widget_move (&tree->widget, line, 1);
169 hline (' ', tree_cols);
170 widget_move (&tree->widget, line, 1);
172 if (tree->searching){
173 /* Show search string */
174 attrset (TREE_NORMALC (h));
175 attrset (DLG_FOCUSC (h));
176 addch (PATH_SEP);
178 addstr ((char *) name_trunc (tree->search_buffer, tree_cols-2));
179 addch (' ');
180 attrset (DLG_FOCUSC (h));
181 } else {
182 /* Show full name of selected directory */
183 addstr ((char *) name_trunc (tree->selected_ptr->name, tree_cols));
187 static void show_tree (WTree *tree)
189 Dlg_head *h = tree->widget.parent;
190 tree_entry *current;
191 int i, j, topsublevel;
192 int x, y;
193 int tree_lines, tree_cols;
195 /* Initialize */
196 x = y = 0;
197 tree_lines = tlines (tree);
198 tree_cols = tree->widget.cols;
200 attrset (TREE_NORMALC (h));
201 widget_move ((Widget*)tree, y, x);
202 if (tree->is_panel){
203 tree_cols -= 2;
204 x = y = 1;
207 g_free (tree->tree_shown);
208 tree->tree_shown = g_new (tree_entry*, tree_lines);
210 for (i = 0; i < tree_lines; i++)
211 tree->tree_shown [i] = NULL;
212 if (tree->store->tree_first)
213 topsublevel = tree->store->tree_first->sublevel;
214 else
215 topsublevel = 0;
216 if (!tree->selected_ptr){
217 tree->selected_ptr = tree->store->tree_first;
218 tree->topdiff = 0;
220 current = tree->selected_ptr;
222 /* Calculate the directory which is to be shown on the topmost line */
223 if (tree_navigation_flag){
224 i = 0;
225 while (current->prev && i < tree->topdiff){
226 current = current->prev;
227 if (current->sublevel < tree->selected_ptr->sublevel){
228 if (strncmp (current->name, tree->selected_ptr->name,
229 strlen (current->name)) == 0)
230 i++;
231 } else if (current->sublevel == tree->selected_ptr->sublevel){
232 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
233 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
234 i++;
235 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
236 && strlen (tree->selected_ptr->name) > 1){
237 if (strncmp (current->name, tree->selected_ptr->name,
238 strlen (tree->selected_ptr->name)) == 0)
239 i++;
242 tree->topdiff = i;
243 } else
244 current = back_ptr (current, &tree->topdiff);
246 /* Loop for every line */
247 for (i = 0; i < tree_lines; i++){
248 /* Move to the beginning of the line */
249 widget_move (&tree->widget, y+i, x);
251 hline (' ', tree_cols);
252 widget_move (&tree->widget, y+i, x);
254 if (!current)
255 continue;
257 tree->tree_shown [i] = current;
258 if (current->sublevel == topsublevel){
260 /* Top level directory */
261 if (tree->active && current == tree->selected_ptr) {
262 if (!use_colors && !tree->is_panel)
263 attrset (MARKED_COLOR);
264 else
265 attrset (SELECTED_COLOR);
268 /* Show full name */
269 addstr ((char *) name_trunc (current->name, tree_cols - 6));
270 } else{
271 /* Sub level directory */
273 acs ();
274 /* Output branch parts */
275 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
276 if (tree_cols - 8 - 3 * j < 9)
277 break;
278 addch (' ');
279 if (current->submask & (1 << (j + topsublevel + 1)))
280 addch (ACS_VLINE);
281 else
282 addch (' ');
283 addch (' ');
285 addch (' '); j++;
286 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
287 addch (ACS_LLCORNER);
288 else
289 addch (ACS_LTEE);
290 addch (ACS_HLINE);
291 noacs ();
293 if (tree->active && current == tree->selected_ptr) {
294 /* Selected directory -> change color */
295 if (!use_colors && !tree->is_panel)
296 attrset (MARKED_COLOR);
297 else
298 attrset (SELECTED_COLOR);
301 /* Show sub-name */
302 addch (' ');
303 addstr ((char *) name_trunc (current->subname,
304 tree_cols - 2 - 4 - 3 * j));
306 addch (' ');
308 /* Return to normal color */
309 attrset (TREE_NORMALC (h));
311 /* Calculate the next value for current */
312 current = current->next;
313 if (tree_navigation_flag){
314 while (current){
315 if (current->sublevel < tree->selected_ptr->sublevel){
316 if (strncmp (current->name, tree->selected_ptr->name,
317 strlen (current->name)) == 0)
318 break;
319 } else if (current->sublevel == tree->selected_ptr->sublevel){
320 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
321 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
322 break;
323 } else if (current->sublevel == tree->selected_ptr->sublevel+1
324 && strlen (tree->selected_ptr->name) > 1){
325 if (strncmp (current->name, tree->selected_ptr->name,
326 strlen (tree->selected_ptr->name)) == 0)
327 break;
329 current = current->next;
333 tree_show_mini_info (tree, tree_lines, tree_cols);
336 static void check_focus (WTree *tree)
338 if (tree->topdiff < 3)
339 tree->topdiff = 3;
340 else if (tree->topdiff >= tlines (tree) - 3)
341 tree->topdiff = tlines (tree) - 3 - 1;
344 static void tree_move_backward (WTree *tree, int i)
346 tree_entry *current;
347 int j = 0;
349 if (tree_navigation_flag){
350 current = tree->selected_ptr;
351 while (j < i && current->prev
352 && current->prev->sublevel >= tree->selected_ptr->sublevel){
353 current = current->prev;
354 if (current->sublevel == tree->selected_ptr->sublevel){
355 tree->selected_ptr = current;
356 j ++;
359 i = j;
360 } else
361 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
362 tree->topdiff -= i;
363 check_focus (tree);
366 static void tree_move_forward (WTree *tree, int i)
368 tree_entry *current;
369 int j = 0;
371 if (tree_navigation_flag){
372 current = tree->selected_ptr;
373 while (j < i && current->next
374 && current->next->sublevel >= tree->selected_ptr->sublevel){
375 current = current->next;
376 if (current->sublevel == tree->selected_ptr->sublevel){
377 tree->selected_ptr = current;
378 j ++;
381 i = j;
382 } else
383 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
384 tree->topdiff += i;
385 check_focus (tree);
388 static void tree_move_to_child (WTree *tree)
390 tree_entry *current;
392 /* Do we have a starting point? */
393 if (!tree->selected_ptr)
394 return;
395 /* Take the next entry */
396 current = tree->selected_ptr->next;
397 /* Is it the child of the selected entry */
398 if (current && current->sublevel > tree->selected_ptr->sublevel){
399 /* Yes -> select this entry */
400 tree->selected_ptr = current;
401 tree->topdiff++;
402 check_focus (tree);
403 } else {
404 /* No -> rescan and try again */
405 tree_rescan_cmd (tree);
406 current = tree->selected_ptr->next;
407 if (current && current->sublevel > tree->selected_ptr->sublevel){
408 tree->selected_ptr = current;
409 tree->topdiff++;
410 check_focus (tree);
415 static int tree_move_to_parent (WTree *tree)
417 tree_entry *current;
418 tree_entry *old;
420 if (!tree->selected_ptr)
421 return 0;
422 old = tree->selected_ptr;
423 current = tree->selected_ptr->prev;
424 while (current && current->sublevel >= tree->selected_ptr->sublevel){
425 current = current->prev;
426 tree->topdiff--;
428 if (!current)
429 current = tree->store->tree_first;
430 tree->selected_ptr = current;
431 check_focus (tree);
432 return tree->selected_ptr != old;
435 static void tree_move_to_top (WTree *tree)
437 tree->selected_ptr = tree->store->tree_first;
438 tree->topdiff = 0;
441 static void tree_move_to_bottom (WTree *tree)
443 tree->selected_ptr = tree->store->tree_last;
444 tree->topdiff = tlines (tree) - 3 - 1;
447 void tree_chdir (WTree *tree, const char *dir)
449 tree_entry *current;
451 current = tree_store_whereis (dir);
452 if (current){
453 tree->selected_ptr = current;
454 check_focus (tree);
458 void
459 sync_tree (const char *path)
461 tree_chdir (the_tree, path);
464 /* Handle mouse click */
465 static void
466 tree_event (WTree *tree, int y)
468 if (tree->tree_shown [y]){
469 tree->selected_ptr = tree->tree_shown [y];
470 tree->topdiff = y;
472 show_tree (tree);
475 static void chdir_sel (WTree *tree);
477 static void maybe_chdir (WTree *tree)
479 if (!(xtree_mode && tree->is_panel))
480 return;
481 if (is_idle ())
482 chdir_sel (tree);
485 /* Mouse callback */
486 static int
487 event_callback (Gpm_Event *event, void *data)
489 WTree *tree = data;
491 if (!(event->type & GPM_UP))
492 return MOU_NORMAL;
494 if (tree->is_panel)
495 event->y--;
497 event->y--;
499 if (!tree->active)
500 change_panel ();
502 if (event->y < 0){
503 tree_move_backward (tree, tlines (tree) - 1);
504 show_tree (tree);
506 else if (event->y >= tlines (tree)){
507 tree_move_forward (tree, tlines (tree) - 1);
508 show_tree (tree);
509 } else {
510 tree_event (tree, event->y);
511 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
512 chdir_sel (tree);
515 return MOU_NORMAL;
518 /* Search tree for text */
519 static int search_tree (WTree *tree, char *text)
521 tree_entry *current;
522 int len;
523 int wrapped = 0;
524 int found = 0;
526 len = strlen (text);
527 current = tree->selected_ptr;
528 found = 0;
529 while (!wrapped || current != tree->selected_ptr){
530 if (strncmp (current->subname, text, len) == 0){
531 tree->selected_ptr = current;
532 found = 1;
533 break;
535 current = current->next;
536 if (!current){
537 current = tree->store->tree_first;
538 wrapped = 1;
540 tree->topdiff++;
542 check_focus (tree);
543 return found;
546 static void tree_do_search (WTree *tree, int key)
548 size_t l;
550 l = strlen (tree->search_buffer);
551 if (l && (key == KEY_BACKSPACE))
552 tree->search_buffer [--l] = 0;
553 else {
554 if (key && l < sizeof (tree->search_buffer)){
555 tree->search_buffer [l] = key;
556 tree->search_buffer [l+1] = 0;
557 l++;
561 if (!search_tree (tree, tree->search_buffer))
562 tree->search_buffer [--l] = 0;
564 show_tree (tree);
565 maybe_chdir (tree);
568 static void
569 tree_rescan_cmd (WTree *tree)
571 char old_dir [MC_MAXPATHLEN];
573 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
574 mc_chdir (tree->selected_ptr->name))
575 return;
577 tree_store_rescan (tree->selected_ptr->name);
578 mc_chdir (old_dir);
581 static void
582 tree_forget_cmd (void *data)
584 WTree *tree = data;
585 if (tree->selected_ptr)
586 tree_remove_entry (tree, tree->selected_ptr->name);
589 static void tree_copy (WTree *tree, const char *default_dest)
591 char *dest;
592 off_t count = 0;
593 double bytes = 0;
594 FileOpContext *ctx;
596 if (!tree->selected_ptr)
597 return;
598 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
599 name_trunc (tree->selected_ptr->name, 50));
600 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
602 if (!dest)
603 return;
605 if (!*dest){
606 g_free (dest);
607 return;
610 ctx = file_op_context_new (OP_COPY);
611 file_op_context_create_ui (ctx, FALSE);
612 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
613 file_op_context_destroy (ctx);
615 g_free (dest);
618 static void
619 tree_help_cmd (void)
621 interactive_display (NULL, "[Directory Tree]");
624 static void
625 tree_copy_cmd (void *data)
627 WTree *tree = data;
628 tree_copy (tree, "");
631 static void tree_move (WTree *tree, const char *default_dest)
633 char *dest;
634 struct stat buf;
635 double bytes = 0;
636 off_t count = 0;
637 FileOpContext *ctx;
639 if (!tree->selected_ptr)
640 return;
641 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
642 name_trunc (tree->selected_ptr->name, 50));
643 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
644 if (!dest)
645 return;
646 if (!*dest){
647 g_free (dest);
648 return;
650 if (stat (dest, &buf)){
651 message (1, MSG_ERROR, _(" Cannot stat the destination \n %s "),
652 unix_error_string (errno));
653 g_free (dest);
654 return;
656 if (!S_ISDIR (buf.st_mode)){
657 file_error (_(" Destination \"%s\" must be a directory \n %s "),
658 dest);
659 g_free (dest);
660 return;
663 ctx = file_op_context_new (OP_MOVE);
664 file_op_context_create_ui (ctx, FALSE);
665 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
666 file_op_context_destroy (ctx);
668 g_free (dest);
671 static void
672 tree_move_cmd (void *data)
674 WTree *tree = data;
675 tree_move (tree, "");
678 #if 0
679 static void
680 tree_mkdir_cmd (WTree *tree)
682 char old_dir [MC_MAXPATHLEN];
684 if (!tree->selected_ptr)
685 return;
686 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
687 return;
688 if (chdir (tree->selected_ptr->name))
689 return;
690 /* FIXME
691 mkdir_cmd (tree);
693 tree_rescan_cmd (tree);
694 chdir (old_dir);
696 #endif
698 static void
699 tree_rmdir_cmd (WTree *tree)
701 off_t count = 0;
702 double bytes = 0;
703 FileOpContext *ctx;
705 if (!tree->selected_ptr)
706 return;
708 if (confirm_delete) {
709 char *buf;
710 int result;
712 buf =
713 g_strdup_printf (_(" Delete %s? "),
714 tree->selected_ptr->name);
715 result =
716 query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
717 g_free (buf);
718 if (result != 0)
719 return;
722 ctx = file_op_context_new (OP_DELETE);
723 file_op_context_create_ui (ctx, FALSE);
724 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) ==
725 FILE_CONT)
726 tree_forget_cmd (tree);
727 file_op_context_destroy (ctx);
730 static void set_navig_label (WTree *tree);
732 static void
733 tree_toggle_navig (void *data)
735 WTree *tree = data;
736 /* FIXME: invalid use of boolean variable */
737 tree_navigation_flag = 1 - tree_navigation_flag;
738 set_navig_label (tree);
741 static void
742 set_navig_label (WTree *tree)
744 buttonbar_set_label_data (tree->widget.parent, 4,
745 tree_navigation_flag ? _("Static") : _("Dynamc"),
746 tree_toggle_navig, tree);
749 static void
750 move_down (WTree *tree)
752 tree_move_forward (tree, 1);
753 show_tree (tree);
754 maybe_chdir (tree);
757 static void
758 move_up (WTree *tree)
760 tree_move_backward (tree, 1);
761 show_tree (tree);
762 maybe_chdir (tree);
765 static void
766 move_home (WTree *tree)
768 tree_move_to_top (tree);
769 show_tree (tree);
770 maybe_chdir (tree);
773 static void
774 move_end (WTree *tree)
776 tree_move_to_bottom (tree);
777 show_tree (tree);
778 maybe_chdir (tree);
781 static int
782 move_left (WTree *tree)
784 int v;
786 if (tree_navigation_flag){
787 v = tree_move_to_parent (tree);
788 show_tree (tree);
789 maybe_chdir (tree);
790 return v;
792 return 0;
795 static int
796 move_right (WTree *tree)
798 if (tree_navigation_flag){
799 tree_move_to_child (tree);
800 show_tree (tree);
801 maybe_chdir (tree);
802 return 1;
804 return 0;
807 static void
808 move_prevp (WTree *tree)
810 tree_move_backward (tree, tlines (tree) - 1);
811 show_tree (tree);
812 maybe_chdir (tree);
815 static void
816 move_nextp (WTree *tree)
818 tree_move_forward (tree, tlines (tree) - 1);
819 show_tree (tree);
820 maybe_chdir (tree);
823 static void
824 chdir_sel (WTree *tree)
826 if (!tree->is_panel) {
827 return;
829 change_panel ();
830 if (do_cd (tree->selected_ptr->name, cd_exact)) {
831 select_item (current_panel);
832 } else {
833 message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
834 tree->selected_ptr->name, unix_error_string (errno));
836 change_panel ();
837 show_tree (tree);
838 return;
841 static void
842 tree_start_search (WTree *tree)
844 int i;
846 if (tree->searching){
848 if (tree->selected_ptr == tree->store->tree_last)
849 tree_move_to_top(tree);
850 else {
851 /* set navigation mode temporarily to 'Static' because in
852 * dynamic navigation mode tree_move_forward will not move
853 * to a lower sublevel if necessary (sequent searches must
854 * start with the directory followed the last found directory)
856 i = tree_navigation_flag;
857 tree_navigation_flag = 0;
858 tree_move_forward (tree, 1);
859 tree_navigation_flag = i;
861 tree_do_search (tree, 0);
863 else {
864 tree->searching = 1;
865 tree->search_buffer[0] = 0;
869 typedef void (*tree_key_action) (WTree *);
870 typedef struct {
871 int key_code;
872 tree_key_action fn;
873 } tree_key_map;
875 static const tree_key_map tree_keymap [] = {
876 { XCTRL('n'), move_down },
877 { XCTRL('p'), move_up },
878 { KEY_DOWN, move_down },
879 { KEY_UP, move_up },
880 { '\n', chdir_sel },
881 { KEY_ENTER, chdir_sel },
882 { KEY_HOME, move_home },
883 { KEY_A1, move_home },
884 { ALT ('<'), move_home },
885 { KEY_END, move_end },
886 { KEY_C1, move_end },
887 { ALT ('>'), move_end },
888 { KEY_NPAGE, move_nextp },
889 { KEY_PPAGE, move_prevp },
890 { XCTRL('v'), move_nextp },
891 { ALT('v'), move_prevp },
892 { XCTRL('p'), move_up },
893 { XCTRL('p'), move_down },
894 { XCTRL('s'), tree_start_search },
895 { ALT('s'), tree_start_search },
896 { XCTRL('r'), tree_rescan_cmd },
897 { KEY_DC, tree_rmdir_cmd },
898 { 0, 0 }
901 static inline cb_ret_t
902 tree_key (WTree *tree, int key)
904 int i;
906 for (i = 0; tree_keymap [i].key_code; i++){
907 if (key == tree_keymap [i].key_code){
908 if (tree_keymap [i].fn != tree_start_search)
909 tree->searching = 0;
910 (*tree_keymap [i].fn)(tree);
911 show_tree (tree);
912 return MSG_HANDLED;
916 /* We do not want to use them if we do not need to */
917 /* Input line may want to take the motion key event */
918 if (key == KEY_LEFT)
919 return move_left (tree);
921 if (key == KEY_RIGHT)
922 return move_right (tree);
924 if (is_abort_char (key)) {
925 if (tree->is_panel) {
926 tree->searching = 0;
927 show_tree (tree);
928 return MSG_HANDLED; /* eat abort char */
930 /* modal tree dialog: let upper layer see the
931 abort character and close the dialog */
932 return MSG_NOT_HANDLED;
935 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
936 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
937 if (tree->searching){
938 tree_do_search (tree, key);
939 show_tree (tree);
940 return MSG_HANDLED;
943 if (!command_prompt) {
944 tree_start_search (tree);
945 tree_do_search (tree, key);
946 return MSG_HANDLED;
948 return tree->is_panel;
951 return MSG_NOT_HANDLED;
954 static void
955 tree_frame (Dlg_head *h, WTree *tree)
957 attrset (NORMAL_COLOR);
958 widget_erase ((Widget*) tree);
959 if (tree->is_panel)
960 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
961 tree->widget.cols);
963 if (show_mini_info && tree->is_panel){
964 widget_move (tree, tlines (tree) + 1, 1);
965 hline (ACS_HLINE, tree->widget.cols - 2);
969 static void
970 tree_rescan_command (void *data)
972 WTree *tree = data;
973 tree_rescan_cmd (tree);
976 static void
977 tree_rmdir_command (void *data)
979 WTree *tree = data;
980 tree_rmdir_cmd (tree);
983 static cb_ret_t
984 tree_callback (Widget *w, widget_msg_t msg, int parm)
986 WTree *tree = (WTree *) w;
987 Dlg_head *h = tree->widget.parent;
989 switch (msg) {
990 case WIDGET_DRAW:
991 tree_frame (h, tree);
992 show_tree (tree);
993 return MSG_HANDLED;
995 case WIDGET_KEY:
996 return tree_key (tree, parm);
998 case WIDGET_FOCUS:
999 tree->active = 1;
1000 buttonbar_set_label (h, 1, _("Help"), tree_help_cmd);
1001 buttonbar_set_label_data (h, 2, _("Rescan"),
1002 tree_rescan_command, tree);
1003 buttonbar_set_label_data (h, 3, _("Forget"), tree_forget_cmd, tree);
1004 buttonbar_set_label_data (h, 5, _("Copy"), tree_copy_cmd, tree);
1005 buttonbar_set_label_data (h, 6, _("RenMov"), tree_move_cmd, tree);
1006 #if 0
1007 /* FIXME: mkdir is currently defunct */
1008 buttonbar_set_label_data (h, 7, _("Mkdir"), tree_mkdir_cmd, tree);
1009 #else
1010 buttonbar_clear_label (h, 7);
1011 #endif
1012 buttonbar_set_label_data (h, 8, _("Rmdir"), tree_rmdir_command, tree);
1013 set_navig_label (tree);
1014 buttonbar_redraw (h);
1017 /* FIXME: Should find a better way of only displaying the
1018 currently selected item */
1019 show_tree (tree);
1020 return MSG_HANDLED;
1022 /* FIXME: Should find a better way of changing the color of the
1023 selected item */
1025 case WIDGET_UNFOCUS:
1026 tree->active = 0;
1027 show_tree (tree);
1028 return MSG_HANDLED;
1030 case WIDGET_DESTROY:
1031 tree_destroy (tree);
1032 return MSG_HANDLED;
1034 default:
1035 return default_proc (msg, parm);
1039 WTree *
1040 tree_new (int is_panel, int y, int x, int lines, int cols)
1042 WTree *tree = g_new (WTree, 1);
1044 init_widget (&tree->widget, y, x, lines, cols,
1045 tree_callback, event_callback);
1046 tree->is_panel = is_panel;
1047 tree->selected_ptr = 0;
1049 tree->store = tree_store_get ();
1050 tree_store_add_entry_remove_hook (remove_callback, tree);
1051 tree->tree_shown = 0;
1052 tree->search_buffer[0] = 0;
1053 tree->topdiff = tree->widget.lines / 2;
1054 tree->searching = 0;
1055 tree->active = 0;
1057 /* We do not want to keep the cursor */
1058 widget_want_cursor (tree->widget, 0);
1059 load_tree (tree);
1060 return tree;
1063 /* Return name of the currently selected entry */
1064 char *
1065 tree_selected_name (WTree *tree)
1067 return tree->selected_ptr->name;