More translates of doc/man/es/mc.1.in
[midnight-commander.git] / src / tree.c
blob51ebfa92026120b71bf1c8f610b81c2f0c73a85a
1 /* Directory tree browser for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
5 Written: 1994, 1996 Janne Kukonlehto
6 1997 Norbert Warmuth
7 1996, 1999 Miguel de Icaza
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 This module has been converted to be a widget.
25 The program load and saves the tree each time the tree widget is
26 created and destroyed. This is required for the future vfs layer,
27 it will be possible to have tree views over virtual file systems.
31 /** \file tree.c
32 * \brief Source: directory tree browser
35 #include <config.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
41 #include "global.h"
43 #include "../src/tty/tty.h"
44 #include "../src/tty/color.h"
45 #include "../src/tty/mouse.h"
46 #include "../src/tty/key.h"
48 #include "wtools.h" /* message() */
49 #include "dir.h"
50 #include "dialog.h"
51 #include "widget.h"
52 #include "panel.h"
53 #include "main.h"
54 #include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
55 #include "help.h"
56 #include "tree.h"
57 #include "treestore.h"
58 #include "cmd.h"
59 #include "history.h"
60 #include "strutil.h"
62 #define tlines(t) (t->is_panel ? t->widget.lines-2 - (show_mini_info ? 2 : 0) : t->widget.lines)
64 extern int command_prompt;
66 /* Use the color of the parent widget for the unselected entries */
67 #define TREE_NORMALC(h) (DLG_NORMALC (h))
69 /* Specifies the display mode: 1d or 2d */
70 static int tree_navigation_flag;
72 struct WTree {
73 Widget widget;
74 struct TreeStore *store;
75 tree_entry *selected_ptr; /* The selected directory */
76 char search_buffer[256]; /* Current search string */
77 tree_entry **tree_shown; /* Entries currently on screen */
78 int is_panel; /* panel or plain widget flag */
79 int active; /* if it's currently selected */
80 int searching; /* Are we on searching mode? */
81 int topdiff; /* The difference between the topmost
82 shown and the selected */
85 /* Forwards */
86 static void save_tree (WTree *tree);
87 static void tree_rescan_cmd (WTree *);
89 static tree_entry *back_ptr (tree_entry *ptr, int *count)
91 int i = 0;
93 while (ptr && ptr->prev && i < *count){
94 ptr = ptr->prev;
95 i ++;
97 *count = i;
98 return ptr;
101 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
103 int i = 0;
105 while (ptr && ptr->next && i < *count){
106 ptr = ptr->next;
107 i ++;
109 *count = i;
110 return ptr;
113 static void
114 remove_callback (tree_entry *entry, void *data)
116 WTree *tree = data;
118 if (tree->selected_ptr == entry){
119 if (tree->selected_ptr->next)
120 tree->selected_ptr = tree->selected_ptr->next;
121 else
122 tree->selected_ptr = tree->selected_ptr->prev;
126 static void tree_remove_entry (WTree *tree, char *name)
128 (void) tree;
129 tree_store_remove_entry (name);
132 static void tree_destroy (WTree *tree)
134 tree_store_remove_entry_remove_hook (remove_callback);
135 save_tree (tree);
137 g_free (tree->tree_shown);
138 tree->tree_shown = 0;
139 tree->selected_ptr = NULL;
142 /* Loads the .mc.tree file */
143 static void load_tree (WTree *tree)
145 tree_store_load ();
147 tree->selected_ptr = tree->store->tree_first;
148 tree_chdir (tree, home_dir);
151 /* Save the .mc.tree file */
152 static void save_tree (WTree *tree)
154 int error;
156 (void) tree;
157 error = tree_store_save ();
159 if (error){
160 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
161 unix_error_string (error));
165 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
167 Dlg_head *h = tree->widget.parent;
168 int line;
170 /* Show mini info */
171 if (tree->is_panel){
172 if (!show_mini_info)
173 return;
174 line = tree_lines+2;
175 } else
176 line = tree_lines+1;
178 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
179 widget_move (&tree->widget, line, 1);
181 if (tree->searching){
182 /* Show search string */
183 tty_setcolor (TREE_NORMALC (h));
184 tty_setcolor (DLG_FOCUSC (h));
185 tty_print_char (PATH_SEP);
187 tty_print_string (str_fit_to_term (tree->search_buffer,
188 tree_cols - 2, J_LEFT_FIT));
189 tty_print_char (' ');
190 tty_setcolor (DLG_FOCUSC (h));
191 } else {
192 /* Show full name of selected directory */
193 tty_print_string (str_fit_to_term (tree->selected_ptr->name,
194 tree_cols, J_LEFT_FIT));
198 static void show_tree (WTree *tree)
200 Dlg_head *h = tree->widget.parent;
201 tree_entry *current;
202 int i, j, topsublevel;
203 int x, y;
204 int tree_lines, tree_cols;
206 /* Initialize */
207 x = y = 0;
208 tree_lines = tlines (tree);
209 tree_cols = tree->widget.cols;
211 tty_setcolor (TREE_NORMALC (h));
212 widget_move ((Widget*)tree, y, x);
213 if (tree->is_panel){
214 tree_cols -= 2;
215 x = y = 1;
218 g_free (tree->tree_shown);
219 tree->tree_shown = g_new (tree_entry*, tree_lines);
221 for (i = 0; i < tree_lines; i++)
222 tree->tree_shown [i] = NULL;
223 if (tree->store->tree_first)
224 topsublevel = tree->store->tree_first->sublevel;
225 else
226 topsublevel = 0;
227 if (!tree->selected_ptr){
228 tree->selected_ptr = tree->store->tree_first;
229 tree->topdiff = 0;
231 current = tree->selected_ptr;
233 /* Calculate the directory which is to be shown on the topmost line */
234 if (tree_navigation_flag){
235 i = 0;
236 while (current->prev && i < tree->topdiff){
237 current = current->prev;
238 if (current->sublevel < tree->selected_ptr->sublevel){
239 if (strncmp (current->name, tree->selected_ptr->name,
240 strlen (current->name)) == 0)
241 i++;
242 } else if (current->sublevel == tree->selected_ptr->sublevel){
243 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
244 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
245 i++;
246 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
247 && strlen (tree->selected_ptr->name) > 1){
248 if (strncmp (current->name, tree->selected_ptr->name,
249 strlen (tree->selected_ptr->name)) == 0)
250 i++;
253 tree->topdiff = i;
254 } else
255 current = back_ptr (current, &tree->topdiff);
257 /* Loop for every line */
258 for (i = 0; i < tree_lines; i++){
259 /* Move to the beginning of the line */
260 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x,
261 ' ', tree_cols);
263 if (!current)
264 continue;
266 tree->tree_shown [i] = current;
267 if (current->sublevel == topsublevel){
269 /* Top level directory */
270 if (tree->active && current == tree->selected_ptr) {
271 if (!tty_use_colors () && !tree->is_panel)
272 tty_setcolor (MARKED_COLOR);
273 else
274 tty_setcolor (SELECTED_COLOR);
277 /* Show full name */
278 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
279 } else{
280 /* Sub level directory */
282 tty_set_alt_charset (TRUE);
283 /* Output branch parts */
284 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
285 if (tree_cols - 8 - 3 * j < 9)
286 break;
287 tty_print_char (' ');
288 if (current->submask & (1 << (j + topsublevel + 1)))
289 tty_print_char (ACS_VLINE);
290 else
291 tty_print_char (' ');
292 tty_print_char (' ');
294 tty_print_char (' '); j++;
295 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
296 tty_print_char (ACS_LLCORNER);
297 else
298 tty_print_char (ACS_LTEE);
299 tty_print_char (ACS_HLINE);
300 tty_set_alt_charset (FALSE);
302 if (tree->active && current == tree->selected_ptr) {
303 /* Selected directory -> change color */
304 if (!tty_use_colors () && !tree->is_panel)
305 tty_setcolor (MARKED_COLOR);
306 else
307 tty_setcolor (SELECTED_COLOR);
310 /* Show sub-name */
311 tty_print_char (' ');
312 tty_print_string (str_fit_to_term (current->subname,
313 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
315 tty_print_char (' ');
317 /* Return to normal color */
318 tty_setcolor (TREE_NORMALC (h));
320 /* Calculate the next value for current */
321 current = current->next;
322 if (tree_navigation_flag){
323 while (current){
324 if (current->sublevel < tree->selected_ptr->sublevel){
325 if (strncmp (current->name, tree->selected_ptr->name,
326 strlen (current->name)) == 0)
327 break;
328 } else if (current->sublevel == tree->selected_ptr->sublevel){
329 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
330 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
331 break;
332 } else if (current->sublevel == tree->selected_ptr->sublevel+1
333 && strlen (tree->selected_ptr->name) > 1){
334 if (strncmp (current->name, tree->selected_ptr->name,
335 strlen (tree->selected_ptr->name)) == 0)
336 break;
338 current = current->next;
342 tree_show_mini_info (tree, tree_lines, tree_cols);
345 static void check_focus (WTree *tree)
347 if (tree->topdiff < 3)
348 tree->topdiff = 3;
349 else if (tree->topdiff >= tlines (tree) - 3)
350 tree->topdiff = tlines (tree) - 3 - 1;
353 static void tree_move_backward (WTree *tree, int i)
355 tree_entry *current;
356 int j = 0;
358 if (tree_navigation_flag){
359 current = tree->selected_ptr;
360 while (j < i && current->prev
361 && current->prev->sublevel >= tree->selected_ptr->sublevel){
362 current = current->prev;
363 if (current->sublevel == tree->selected_ptr->sublevel){
364 tree->selected_ptr = current;
365 j ++;
368 i = j;
369 } else
370 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
371 tree->topdiff -= i;
372 check_focus (tree);
375 static void tree_move_forward (WTree *tree, int i)
377 tree_entry *current;
378 int j = 0;
380 if (tree_navigation_flag){
381 current = tree->selected_ptr;
382 while (j < i && current->next
383 && current->next->sublevel >= tree->selected_ptr->sublevel){
384 current = current->next;
385 if (current->sublevel == tree->selected_ptr->sublevel){
386 tree->selected_ptr = current;
387 j ++;
390 i = j;
391 } else
392 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
393 tree->topdiff += i;
394 check_focus (tree);
397 static void tree_move_to_child (WTree *tree)
399 tree_entry *current;
401 /* Do we have a starting point? */
402 if (!tree->selected_ptr)
403 return;
404 /* Take the next entry */
405 current = tree->selected_ptr->next;
406 /* Is it the child of the selected entry */
407 if (current && current->sublevel > tree->selected_ptr->sublevel){
408 /* Yes -> select this entry */
409 tree->selected_ptr = current;
410 tree->topdiff++;
411 check_focus (tree);
412 } else {
413 /* No -> rescan and try again */
414 tree_rescan_cmd (tree);
415 current = tree->selected_ptr->next;
416 if (current && current->sublevel > tree->selected_ptr->sublevel){
417 tree->selected_ptr = current;
418 tree->topdiff++;
419 check_focus (tree);
424 static int tree_move_to_parent (WTree *tree)
426 tree_entry *current;
427 tree_entry *old;
429 if (!tree->selected_ptr)
430 return 0;
431 old = tree->selected_ptr;
432 current = tree->selected_ptr->prev;
433 while (current && current->sublevel >= tree->selected_ptr->sublevel){
434 current = current->prev;
435 tree->topdiff--;
437 if (!current)
438 current = tree->store->tree_first;
439 tree->selected_ptr = current;
440 check_focus (tree);
441 return tree->selected_ptr != old;
444 static void tree_move_to_top (WTree *tree)
446 tree->selected_ptr = tree->store->tree_first;
447 tree->topdiff = 0;
450 static void tree_move_to_bottom (WTree *tree)
452 tree->selected_ptr = tree->store->tree_last;
453 tree->topdiff = tlines (tree) - 3 - 1;
456 void tree_chdir (WTree *tree, const char *dir)
458 tree_entry *current;
460 current = tree_store_whereis (dir);
461 if (current){
462 tree->selected_ptr = current;
463 check_focus (tree);
467 void
468 sync_tree (const char *path)
470 tree_chdir (the_tree, path);
473 /* Handle mouse click */
474 static void
475 tree_event (WTree *tree, int y)
477 if (tree->tree_shown [y]){
478 tree->selected_ptr = tree->tree_shown [y];
479 tree->topdiff = y;
481 show_tree (tree);
484 static void chdir_sel (WTree *tree);
486 static void maybe_chdir (WTree *tree)
488 if (!(xtree_mode && tree->is_panel))
489 return;
490 if (is_idle ())
491 chdir_sel (tree);
494 /* Mouse callback */
495 static int
496 event_callback (Gpm_Event *event, void *data)
498 WTree *tree = data;
500 if (!(event->type & GPM_UP))
501 return MOU_NORMAL;
503 if (tree->is_panel)
504 event->y--;
506 event->y--;
508 if (!tree->active)
509 change_panel ();
511 if (event->y < 0){
512 tree_move_backward (tree, tlines (tree) - 1);
513 show_tree (tree);
515 else if (event->y >= tlines (tree)){
516 tree_move_forward (tree, tlines (tree) - 1);
517 show_tree (tree);
518 } else {
519 tree_event (tree, event->y);
520 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
521 chdir_sel (tree);
524 return MOU_NORMAL;
527 /* Search tree for text */
528 static int search_tree (WTree *tree, char *text)
530 tree_entry *current;
531 int len;
532 int wrapped = 0;
533 int found = 0;
535 len = strlen (text);
536 current = tree->selected_ptr;
537 found = 0;
538 while (!wrapped || current != tree->selected_ptr){
539 if (strncmp (current->subname, text, len) == 0){
540 tree->selected_ptr = current;
541 found = 1;
542 break;
544 current = current->next;
545 if (!current){
546 current = tree->store->tree_first;
547 wrapped = 1;
549 tree->topdiff++;
551 check_focus (tree);
552 return found;
555 static void tree_do_search (WTree *tree, int key)
557 size_t l;
559 l = strlen (tree->search_buffer);
560 if (l && (key == KEY_BACKSPACE))
561 tree->search_buffer [--l] = 0;
562 else {
563 if (key && l < sizeof (tree->search_buffer)){
564 tree->search_buffer [l] = key;
565 tree->search_buffer [l+1] = 0;
566 l++;
570 if (!search_tree (tree, tree->search_buffer))
571 tree->search_buffer [--l] = 0;
573 show_tree (tree);
574 maybe_chdir (tree);
577 static void
578 tree_rescan_cmd (WTree *tree)
580 char old_dir [MC_MAXPATHLEN];
582 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
583 mc_chdir (tree->selected_ptr->name))
584 return;
586 tree_store_rescan (tree->selected_ptr->name);
587 mc_chdir (old_dir);
590 static void
591 tree_forget_cmd (void *data)
593 WTree *tree = data;
594 if (tree->selected_ptr)
595 tree_remove_entry (tree, tree->selected_ptr->name);
598 static void tree_copy (WTree *tree, const char *default_dest)
600 char *dest;
601 off_t count = 0;
602 double bytes = 0;
603 FileOpContext *ctx;
605 if (!tree->selected_ptr)
606 return;
607 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
608 str_trunc (tree->selected_ptr->name, 50));
609 dest = input_expand_dialog (_(" Copy "), cmd_buf, MC_HISTORY_FM_TREE_COPY, default_dest);
611 if (!dest)
612 return;
614 if (!*dest){
615 g_free (dest);
616 return;
619 ctx = file_op_context_new (OP_COPY);
620 file_op_context_create_ui (ctx, FALSE);
621 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
622 file_op_context_destroy (ctx);
624 g_free (dest);
627 static void
628 tree_help_cmd (void)
630 interactive_display (NULL, "[Directory Tree]");
633 static void
634 tree_copy_cmd (void *data)
636 WTree *tree = data;
637 tree_copy (tree, "");
640 static void tree_move (WTree *tree, const char *default_dest)
642 char *dest;
643 struct stat buf;
644 double bytes = 0;
645 off_t count = 0;
646 FileOpContext *ctx;
648 if (!tree->selected_ptr)
649 return;
650 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
651 str_trunc (tree->selected_ptr->name, 50));
652 dest = input_expand_dialog (_(" Move "), cmd_buf, MC_HISTORY_FM_TREE_MOVE, default_dest);
653 if (!dest)
654 return;
655 if (!*dest){
656 g_free (dest);
657 return;
659 if (stat (dest, &buf)){
660 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
661 unix_error_string (errno));
662 g_free (dest);
663 return;
665 if (!S_ISDIR (buf.st_mode)){
666 file_error (_(" Destination \"%s\" must be a directory \n %s "),
667 dest);
668 g_free (dest);
669 return;
672 ctx = file_op_context_new (OP_MOVE);
673 file_op_context_create_ui (ctx, FALSE);
674 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
675 file_op_context_destroy (ctx);
677 g_free (dest);
680 static void
681 tree_move_cmd (void *data)
683 WTree *tree = data;
684 tree_move (tree, "");
687 #if 0
688 static void
689 tree_mkdir_cmd (WTree *tree)
691 char old_dir [MC_MAXPATHLEN];
693 if (!tree->selected_ptr)
694 return;
695 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
696 return;
697 if (chdir (tree->selected_ptr->name))
698 return;
699 /* FIXME
700 mkdir_cmd (tree);
702 tree_rescan_cmd (tree);
703 chdir (old_dir);
705 #endif
707 static void
708 tree_rmdir_cmd (WTree *tree)
710 off_t count = 0;
711 double bytes = 0;
712 FileOpContext *ctx;
714 if (!tree->selected_ptr)
715 return;
717 if (confirm_delete) {
718 char *buf;
719 int result;
721 buf =
722 g_strdup_printf (_(" Delete %s? "),
723 tree->selected_ptr->name);
724 result =
725 query_dialog (_(" Delete "), buf, D_ERROR, 2, _("&Yes"), _("&No"));
726 g_free (buf);
727 if (result != 0)
728 return;
731 ctx = file_op_context_new (OP_DELETE);
732 file_op_context_create_ui (ctx, FALSE);
733 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) ==
734 FILE_CONT)
735 tree_forget_cmd (tree);
736 file_op_context_destroy (ctx);
739 static void set_navig_label (WTree *tree);
741 static void
742 tree_toggle_navig (void *data)
744 WTree *tree = data;
745 /* FIXME: invalid use of boolean variable */
746 tree_navigation_flag = 1 - tree_navigation_flag;
747 set_navig_label (tree);
750 static void
751 set_navig_label (WTree *tree)
753 buttonbar_set_label_data (tree->widget.parent, 4,
754 tree_navigation_flag ? _("Static") : _("Dynamc"),
755 tree_toggle_navig, tree);
758 static void
759 move_down (WTree *tree)
761 tree_move_forward (tree, 1);
762 show_tree (tree);
763 maybe_chdir (tree);
766 static void
767 move_up (WTree *tree)
769 tree_move_backward (tree, 1);
770 show_tree (tree);
771 maybe_chdir (tree);
774 static void
775 move_home (WTree *tree)
777 tree_move_to_top (tree);
778 show_tree (tree);
779 maybe_chdir (tree);
782 static void
783 move_end (WTree *tree)
785 tree_move_to_bottom (tree);
786 show_tree (tree);
787 maybe_chdir (tree);
790 static int
791 move_left (WTree *tree)
793 int v;
795 if (tree_navigation_flag){
796 v = tree_move_to_parent (tree);
797 show_tree (tree);
798 maybe_chdir (tree);
799 return v;
801 return 0;
804 static int
805 move_right (WTree *tree)
807 if (tree_navigation_flag){
808 tree_move_to_child (tree);
809 show_tree (tree);
810 maybe_chdir (tree);
811 return 1;
813 return 0;
816 static void
817 move_prevp (WTree *tree)
819 tree_move_backward (tree, tlines (tree) - 1);
820 show_tree (tree);
821 maybe_chdir (tree);
824 static void
825 move_nextp (WTree *tree)
827 tree_move_forward (tree, tlines (tree) - 1);
828 show_tree (tree);
829 maybe_chdir (tree);
832 static void
833 chdir_sel (WTree *tree)
835 if (!tree->is_panel) {
836 return;
838 change_panel ();
839 if (do_cd (tree->selected_ptr->name, cd_exact)) {
840 select_item (current_panel);
841 } else {
842 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
843 tree->selected_ptr->name, unix_error_string (errno));
845 change_panel ();
846 show_tree (tree);
847 return;
850 static void
851 tree_start_search (WTree *tree)
853 int i;
855 if (tree->searching){
857 if (tree->selected_ptr == tree->store->tree_last)
858 tree_move_to_top(tree);
859 else {
860 /* set navigation mode temporarily to 'Static' because in
861 * dynamic navigation mode tree_move_forward will not move
862 * to a lower sublevel if necessary (sequent searches must
863 * start with the directory followed the last found directory)
865 i = tree_navigation_flag;
866 tree_navigation_flag = 0;
867 tree_move_forward (tree, 1);
868 tree_navigation_flag = i;
870 tree_do_search (tree, 0);
872 else {
873 tree->searching = 1;
874 tree->search_buffer[0] = 0;
878 typedef void (*tree_key_action) (WTree *);
879 typedef struct {
880 int key_code;
881 tree_key_action fn;
882 } tree_key_map;
884 static const tree_key_map tree_keymap [] = {
885 { XCTRL('n'), move_down },
886 { XCTRL('p'), move_up },
887 { KEY_DOWN, move_down },
888 { KEY_UP, move_up },
889 { '\n', chdir_sel },
890 { KEY_ENTER, chdir_sel },
891 { KEY_HOME, move_home },
892 { KEY_A1, move_home },
893 { ALT ('<'), move_home },
894 { KEY_END, move_end },
895 { KEY_C1, move_end },
896 { ALT ('>'), move_end },
897 { KEY_NPAGE, move_nextp },
898 { KEY_PPAGE, move_prevp },
899 { XCTRL('v'), move_nextp },
900 { ALT('v'), move_prevp },
901 { XCTRL('p'), move_up },
902 { XCTRL('p'), move_down },
903 { XCTRL('s'), tree_start_search },
904 { ALT('s'), tree_start_search },
905 { XCTRL('r'), tree_rescan_cmd },
906 { KEY_DC, tree_rmdir_cmd },
907 { 0, 0 }
910 static inline cb_ret_t
911 tree_key (WTree *tree, int key)
913 int i;
915 for (i = 0; tree_keymap [i].key_code; i++){
916 if (key == tree_keymap [i].key_code){
917 if (tree_keymap [i].fn != tree_start_search)
918 tree->searching = 0;
919 (*tree_keymap [i].fn)(tree);
920 show_tree (tree);
921 return MSG_HANDLED;
925 /* We do not want to use them if we do not need to */
926 /* Input line may want to take the motion key event */
927 if (key == KEY_LEFT)
928 return move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
930 if (key == KEY_RIGHT)
931 return move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
933 if (is_abort_char (key)) {
934 if (tree->is_panel) {
935 tree->searching = 0;
936 show_tree (tree);
937 return MSG_HANDLED; /* eat abort char */
939 /* modal tree dialog: let upper layer see the
940 abort character and close the dialog */
941 return MSG_NOT_HANDLED;
944 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
945 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
946 if (tree->searching){
947 tree_do_search (tree, key);
948 show_tree (tree);
949 return MSG_HANDLED;
952 if (!command_prompt) {
953 tree_start_search (tree);
954 tree_do_search (tree, key);
955 return MSG_HANDLED;
957 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
960 return MSG_NOT_HANDLED;
963 static void
964 tree_frame (Dlg_head *h, WTree *tree)
966 tty_setcolor (NORMAL_COLOR);
967 widget_erase ((Widget*) tree);
968 if (tree->is_panel) {
969 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
970 tree->widget.cols);
972 if (show_mini_info)
973 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
974 tree->widget.x + 1,
975 ACS_HLINE, tree->widget.cols - 2);
979 static void
980 tree_rescan_command (void *data)
982 WTree *tree = data;
983 tree_rescan_cmd (tree);
986 static void
987 tree_rmdir_command (void *data)
989 WTree *tree = data;
990 tree_rmdir_cmd (tree);
993 static cb_ret_t
994 tree_callback (Widget *w, widget_msg_t msg, int parm)
996 WTree *tree = (WTree *) w;
997 Dlg_head *h = tree->widget.parent;
999 switch (msg) {
1000 case WIDGET_DRAW:
1001 tree_frame (h, tree);
1002 show_tree (tree);
1003 return MSG_HANDLED;
1005 case WIDGET_KEY:
1006 return tree_key (tree, parm);
1008 case WIDGET_FOCUS:
1009 tree->active = 1;
1010 buttonbar_set_label (h, 1, _("Help"), tree_help_cmd);
1011 buttonbar_set_label_data (h, 2, _("Rescan"),
1012 tree_rescan_command, tree);
1013 buttonbar_set_label_data (h, 3, _("Forget"), tree_forget_cmd, tree);
1014 buttonbar_set_label_data (h, 5, _("Copy"), tree_copy_cmd, tree);
1015 buttonbar_set_label_data (h, 6, _("RenMov"), tree_move_cmd, tree);
1016 #if 0
1017 /* FIXME: mkdir is currently defunct */
1018 buttonbar_set_label_data (h, 7, _("Mkdir"), tree_mkdir_cmd, tree);
1019 #else
1020 buttonbar_clear_label (h, 7);
1021 #endif
1022 buttonbar_set_label_data (h, 8, _("Rmdir"), tree_rmdir_command, tree);
1023 set_navig_label (tree);
1024 buttonbar_redraw (h);
1027 /* FIXME: Should find a better way of only displaying the
1028 currently selected item */
1029 show_tree (tree);
1030 return MSG_HANDLED;
1032 /* FIXME: Should find a better way of changing the color of the
1033 selected item */
1035 case WIDGET_UNFOCUS:
1036 tree->active = 0;
1037 show_tree (tree);
1038 return MSG_HANDLED;
1040 case WIDGET_DESTROY:
1041 tree_destroy (tree);
1042 return MSG_HANDLED;
1044 default:
1045 return default_proc (msg, parm);
1049 WTree *
1050 tree_new (int is_panel, int y, int x, int lines, int cols)
1052 WTree *tree = g_new (WTree, 1);
1054 init_widget (&tree->widget, y, x, lines, cols,
1055 tree_callback, event_callback);
1056 tree->is_panel = is_panel;
1057 tree->selected_ptr = 0;
1059 tree->store = tree_store_get ();
1060 tree_store_add_entry_remove_hook (remove_callback, tree);
1061 tree->tree_shown = 0;
1062 tree->search_buffer[0] = 0;
1063 tree->topdiff = tree->widget.lines / 2;
1064 tree->searching = 0;
1065 tree->active = 0;
1067 /* We do not want to keep the cursor */
1068 widget_want_cursor (tree->widget, 0);
1069 load_tree (tree);
1070 return tree;
1073 /* Return name of the currently selected entry */
1074 char *
1075 tree_selected_name (WTree *tree)
1077 return tree->selected_ptr->name;