Codepage messages related translated & other stuff...
[midnight-commander.git] / src / tree.c
blob2e923d7f0799c747c9949584312ca4b630e2beac
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>
33 #include "tty.h"
34 #include "global.h"
35 #include "color.h"
36 #include "dialog.h"
37 #include "dir.h"
38 #include "dlg.h"
39 #include "widget.h"
40 #include "panel.h"
41 #include "mouse.h"
42 #include "main.h"
43 #include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
44 #include "fileopctx.h"
45 #include "help.h"
46 #include "key.h" /* For mi_getch() */
47 #include "tree.h"
48 #include "cmd.h"
49 #include "../vfs/vfs.h"
51 extern int command_prompt;
53 #define TREE_NORMALC HOT_FOCUSC
55 /* Specifies the display mode: 1d or 2d */
56 int tree_navigation_flag;
58 /* Forwards */
59 static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
60 #define tcallback (callback_fn) tree_callback
62 /* "$Id$" */
64 static tree_entry *back_ptr (tree_entry *ptr, int *count)
66 int i = 0;
68 while (ptr && ptr->prev && i < *count){
69 ptr = ptr->prev;
70 i ++;
72 *count = i;
73 return ptr;
76 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
78 int i = 0;
80 while (ptr && ptr->next && i < *count){
81 ptr = ptr->next;
82 i ++;
84 *count = i;
85 return ptr;
88 /* Add a directory to the list of directories */
89 tree_entry *tree_add_entry (WTree *tree, char *name)
91 if (!tree)
92 return 0;
94 return tree_store_add_entry (name);
97 #if 0
98 /* Append a directory to the list of directories */
99 static tree_entry *tree_append_entry (WTree *tree, char *name)
101 tree_entry *current, *new;
102 int i, len;
103 int submask = 0;
105 /* We assume the directory is not yet in the list */
107 new = g_new (tree_entry, 1);
108 if (!tree->store->tree_first){
109 /* Empty list */
110 tree->store->tree_first = new;
111 new->prev = NULL;
112 } else {
113 tree->tree_last->next = new;
114 new->prev = tree->tree_last;
116 new->next = NULL;
117 tree->store->tree_last = new;
119 /* Calculate attributes */
120 new->name = g_strdup (name);
121 len = strlen (new->name);
122 new->sublevel = 0;
123 for (i = 0; i < len; i++)
124 if (new->name [i] == PATH_SEP){
125 new->sublevel++;
126 new->subname = new->name + i + 1;
128 submask = 1 << new->sublevel;
129 submask &= (2 << new->sublevel) - 1;
130 new->submask = submask;
131 new->mark = 0;
133 /* Correct the submasks of the previous entries */
134 current = new->prev;
135 while (current && current->sublevel > new->sublevel){
136 current->submask |= 1 << new->sublevel;
137 current = current->prev;
140 /* The entry has now been appended */
141 return new;
143 #endif
145 void
146 remove_callback (tree_entry *entry, void *data)
148 WTree *tree = data;
150 if (tree->selected_ptr == entry){
151 if (tree->selected_ptr->next)
152 tree->selected_ptr = tree->selected_ptr->next;
153 else
154 tree->selected_ptr = tree->selected_ptr->prev;
158 void tree_remove_entry (WTree *tree, char *name)
160 tree_store_remove_entry (name);
163 void tree_destroy (WTree *tree)
165 tree_store_remove_entry_remove_hook (remove_callback);
166 save_tree (tree);
168 if (tree->tree_shown){
169 g_free (tree->tree_shown);
170 tree->tree_shown = 0;
172 tree->selected_ptr = NULL;
175 /* Loads the .mc.tree file */
176 void load_tree (WTree *tree)
178 tree_store_load ();
180 tree->selected_ptr = tree->store->tree_first;
181 tree_chdir (tree, home_dir);
184 /* Save the .mc.tree file */
185 void save_tree (WTree *tree)
187 int error;
189 error = tree_store_save ();
191 if (error){
192 fprintf (stderr, _("Can't open the %s file for writing:\n%s\n"), MC_TREE,
193 unix_error_string (error));
194 return;
198 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
200 Dlg_head *h = tree->widget.parent;
201 int line;
203 /* Show mini info */
204 if (tree->is_panel){
205 if (!show_mini_info)
206 return;
207 line = tree_lines+2;
208 } else
209 line = tree_lines+1;
211 widget_move (&tree->widget, line, 1);
212 hline (' ', tree_cols);
213 widget_move (&tree->widget, line, 1);
215 if (tree->searching){
216 /* Show search string */
217 attrset (TREE_NORMALC);
218 attrset (FOCUSC);
219 addch (PATH_SEP);
221 addstr (name_trunc (tree->search_buffer, tree_cols-2));
222 addch (' ');
223 attrset (FOCUSC);
224 } else {
225 /* Show full name of selected directory */
226 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
230 void show_tree (WTree *tree)
232 Dlg_head *h = tree->widget.parent;
233 tree_entry *current;
234 int i, j, topsublevel;
235 int x, y;
236 int tree_lines, tree_cols;
238 /* Initialize */
239 x = y = 0;
240 tree_lines = tlines (tree);
241 tree_cols = tree->widget.cols;
243 attrset (TREE_NORMALC);
244 widget_move ((Widget*)tree, y, x);
245 if (tree->is_panel){
246 tree_cols -= 2;
247 x = y = 1;
250 if (tree->tree_shown)
251 g_free (tree->tree_shown);
252 tree->tree_shown = g_new (tree_entry*, tree_lines);
254 for (i = 0; i < tree_lines; i++)
255 tree->tree_shown [i] = NULL;
256 if (tree->store->tree_first)
257 topsublevel = tree->store->tree_first->sublevel;
258 else
259 topsublevel = 0;
260 if (!tree->selected_ptr){
261 tree->selected_ptr = tree->store->tree_first;
262 tree->topdiff = 0;
264 current = tree->selected_ptr;
266 /* Calculate the directory which is to be shown on the topmost line */
267 if (tree_navigation_flag){
268 i = 0;
269 while (current->prev && i < tree->topdiff){
270 current = current->prev;
271 if (current->sublevel < tree->selected_ptr->sublevel){
272 if (strncmp (current->name, tree->selected_ptr->name,
273 strlen (current->name)) == 0)
274 i++;
275 } else if (current->sublevel == tree->selected_ptr->sublevel){
276 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
277 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
278 i++;
279 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
280 && strlen (tree->selected_ptr->name) > 1){
281 if (strncmp (current->name, tree->selected_ptr->name,
282 strlen (tree->selected_ptr->name)) == 0)
283 i++;
286 tree->topdiff = i;
287 } else
288 current = back_ptr (current, &tree->topdiff);
290 /* Loop for every line */
291 for (i = 0; i < tree_lines; i++){
292 /* Move to the beginning of the line */
293 widget_move (&tree->widget, y+i, x);
295 hline (' ', tree_cols);
296 widget_move (&tree->widget, y+i, x);
298 if (!current)
299 continue;
301 tree->tree_shown [i] = current;
302 if (current->sublevel == topsublevel){
304 /* Top level directory */
305 if (tree->active && current == tree->selected_ptr) {
306 if (!use_colors && !tree->is_panel)
307 attrset (MARKED_COLOR);
308 else
309 attrset (SELECTED_COLOR);
312 /* Show full name */
313 addstr (name_trunc (current->name, tree_cols - 6));
314 } else{
315 /* Sub level directory */
317 acs ();
318 /* Output branch parts */
319 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
320 if (tree_cols - 8 - 3 * j < 9)
321 break;
322 addch (' ');
323 if (current->submask & (1 << (j + topsublevel + 1)))
324 addch (ACS_VLINE);
325 else
326 addch (' ');
327 addch (' ');
329 addch (' '); j++;
330 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
331 addch (ACS_LLCORNER);
332 else
333 addch (ACS_LTEE);
334 addch (ACS_HLINE);
335 noacs ();
337 if (tree->active && current == tree->selected_ptr) {
338 /* Selected directory -> change color */
339 if (!use_colors && !tree->is_panel)
340 attrset (MARKED_COLOR);
341 else
342 attrset (SELECTED_COLOR);
345 /* Show sub-name */
346 addch (' ');
347 addstr (name_trunc (current->subname,
348 tree_cols - 2 - 4 - 3 * j));
350 addch (' ');
352 /* Return to normal color */
353 attrset (TREE_NORMALC);
355 /* Calculate the next value for current */
356 if (tree_navigation_flag){
357 current = current->next;
358 while (current){
359 if (current->sublevel < tree->selected_ptr->sublevel){
360 if (strncmp (current->name, tree->selected_ptr->name,
361 strlen (current->name)) == 0)
362 break;
363 } else if (current->sublevel == tree->selected_ptr->sublevel){
364 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
365 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
366 break;
367 } else if (current->sublevel == tree->selected_ptr->sublevel+1
368 && strlen (tree->selected_ptr->name) > 1){
369 if (strncmp (current->name, tree->selected_ptr->name,
370 strlen (tree->selected_ptr->name)) == 0)
371 break;
373 current = current->next;
375 } else
376 current = current->next;
378 tree_show_mini_info (tree, tree_lines, tree_cols);
381 static void check_focus (WTree *tree)
383 if (tree->topdiff < 3)
384 tree->topdiff = 3;
385 else if (tree->topdiff >= tlines (tree) - 3)
386 tree->topdiff = tlines (tree) - 3 - 1;
389 void tree_move_backward (WTree *tree, int i)
391 tree_entry *current;
392 int j = 0;
394 if (tree_navigation_flag){
395 current = tree->selected_ptr;
396 while (j < i && current->prev
397 && current->prev->sublevel >= tree->selected_ptr->sublevel){
398 current = current->prev;
399 if (current->sublevel == tree->selected_ptr->sublevel){
400 tree->selected_ptr = current;
401 j ++;
404 i = j;
405 } else
406 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
407 tree->topdiff -= i;
408 check_focus (tree);
411 void tree_move_forward (WTree *tree, int i)
413 tree_entry *current;
414 int j = 0;
416 if (tree_navigation_flag){
417 current = tree->selected_ptr;
418 while (j < i && current->next
419 && current->next->sublevel >= tree->selected_ptr->sublevel){
420 current = current->next;
421 if (current->sublevel == tree->selected_ptr->sublevel){
422 tree->selected_ptr = current;
423 j ++;
426 i = j;
427 } else
428 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
429 tree->topdiff += i;
430 check_focus (tree);
433 void tree_move_to_child (WTree *tree)
435 tree_entry *current;
437 /* Do we have a starting point? */
438 if (!tree->selected_ptr)
439 return;
440 /* Take the next entry */
441 current = tree->selected_ptr->next;
442 /* Is it the child of the selected entry */
443 if (current && current->sublevel > tree->selected_ptr->sublevel){
444 /* Yes -> select this entry */
445 tree->selected_ptr = current;
446 tree->topdiff++;
447 check_focus (tree);
448 } else {
449 /* No -> rescan and try again */
450 tree_rescan_cmd (tree);
451 current = tree->selected_ptr->next;
452 if (current && current->sublevel > tree->selected_ptr->sublevel){
453 tree->selected_ptr = current;
454 tree->topdiff++;
455 check_focus (tree);
460 int tree_move_to_parent (WTree *tree)
462 tree_entry *current;
463 tree_entry *old;
465 if (!tree->selected_ptr)
466 return 0;
467 old = tree->selected_ptr;
468 current = tree->selected_ptr->prev;
469 while (current && current->sublevel >= tree->selected_ptr->sublevel){
470 current = current->prev;
471 tree->topdiff--;
473 if (!current)
474 current = tree->store->tree_first;
475 tree->selected_ptr = current;
476 check_focus (tree);
477 return tree->selected_ptr != old;
480 void tree_move_to_top (WTree *tree)
482 tree->selected_ptr = tree->store->tree_first;
483 tree->topdiff = 0;
486 void tree_move_to_bottom (WTree *tree)
488 tree->selected_ptr = tree->store->tree_last;
489 tree->topdiff = tlines (tree) - 3 - 1;
492 void tree_chdir (WTree *tree, char *dir)
494 tree_entry *current;
496 current = tree_store_whereis (dir);
497 if (current){
498 tree->selected_ptr = current;
499 check_focus (tree);
503 void
504 sync_tree (char *path)
506 tree_chdir (the_tree, path);
509 /* Handle mouse click */
510 void tree_event (WTree *tree, int y)
512 if (tree->tree_shown [y]){
513 tree->selected_ptr = tree->tree_shown [y];
514 tree->topdiff = y;
516 show_tree (tree);
519 static void chdir_sel (WTree *tree);
521 static void maybe_chdir (WTree *tree)
523 if (!(xtree_mode && tree->is_panel))
524 return;
525 if (is_idle ())
526 chdir_sel (tree);
529 /* Mouse callback */
530 static int event_callback (Gpm_Event *event, WTree *tree)
532 if (!(event->type & GPM_UP))
533 return MOU_ENDLOOP;
535 if (tree->is_panel)
536 event->y--;
538 event->y--;
540 if (!tree->active)
541 change_panel ();
543 if (event->y < 0){
544 tree_move_backward (tree, tlines (tree) - 1);
545 show_tree (tree);
547 else if (event->y >= tlines (tree)){
548 tree_move_forward (tree, tlines (tree) - 1);
549 show_tree (tree);
550 } else {
551 tree_event (tree, event->y);
552 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
553 chdir_sel (tree);
556 return MOU_ENDLOOP;
559 /* Search tree for text */
560 int search_tree (WTree *tree, char *text)
562 tree_entry *current;
563 int len;
564 int wrapped = 0;
565 int found = 0;
567 len = strlen (text);
568 current = tree->selected_ptr;
569 found = 0;
570 while (!wrapped || current != tree->selected_ptr){
571 if (strncmp (current->subname, text, len) == 0){
572 tree->selected_ptr = current;
573 found = 1;
574 break;
576 current = current->next;
577 if (!current){
578 current = tree->store->tree_first;
579 wrapped = 1;
581 tree->topdiff++;
583 check_focus (tree);
584 return found;
587 static void tree_do_search (WTree *tree, int key)
589 int l;
591 l = strlen (tree->search_buffer);
592 if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
593 tree->search_buffer [--l] = 0;
594 else {
595 if (key && l < sizeof (tree->search_buffer)){
596 tree->search_buffer [l] = key;
597 tree->search_buffer [l+1] = 0;
598 l++;
602 if (!search_tree (tree, tree->search_buffer))
603 tree->search_buffer [--l] = 0;
605 show_tree (tree);
606 maybe_chdir (tree);
609 void tree_rescan_cmd (WTree *tree)
611 char old_dir [MC_MAXPATHLEN];
613 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
614 mc_chdir (tree->selected_ptr->name))
615 return;
617 tree_store_rescan (tree->selected_ptr->name);
618 mc_chdir (old_dir);
621 int tree_forget_cmd (WTree *tree)
623 if (tree->selected_ptr)
624 tree_remove_entry (tree, tree->selected_ptr->name);
625 return 1;
628 void tree_copy (WTree *tree, char *default_dest)
630 char *dest;
631 long count = 0;
632 double bytes = 0;
633 FileOpContext *ctx;
635 if (!tree->selected_ptr)
636 return;
637 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
638 name_trunc (tree->selected_ptr->name, 50));
639 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
640 if (!dest || !*dest){
641 return;
644 ctx = file_op_context_new ();
645 file_op_context_create_ui (ctx, OP_COPY, FALSE);
646 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
647 file_op_context_destroy (ctx);
649 g_free (dest);
652 static void tree_help_cmd (void)
654 char *hlpfile = concat_dir_and_file (mc_home, _("mc.hlp"));
655 interactive_display (hlpfile, "[Directory Tree]");
656 g_free (hlpfile);
659 static int tree_copy_cmd (WTree *tree)
661 tree_copy (tree, "");
662 return 1;
665 void tree_move (WTree *tree, char *default_dest)
667 char *dest;
668 struct stat buf;
669 double bytes = 0;
670 long count = 0;
671 FileOpContext *ctx;
673 if (!tree->selected_ptr)
674 return;
675 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
676 name_trunc (tree->selected_ptr->name, 50));
677 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
678 if (!dest || !*dest){
679 return;
681 if (stat (dest, &buf)){
682 message (1, _(" Error "), _(" Can't stat the destination \n %s "),
683 unix_error_string (errno));
684 g_free (dest);
685 return;
687 if (!S_ISDIR (buf.st_mode)){
688 message (1, _(" Error "), _(" The destination isn't a directory "));
689 g_free (dest);
690 return;
693 ctx = file_op_context_new ();
694 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
695 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
696 file_op_context_destroy (ctx);
698 g_free (dest);
701 static int
702 tree_move_cmd (WTree *tree)
704 tree_move (tree, "");
705 return 1;
708 #if 0
709 static int
710 tree_mkdir_cmd (WTree *tree)
712 char old_dir [MC_MAXPATHLEN];
714 if (!tree->selected_ptr)
715 return 0;
716 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
717 return 0;
718 if (chdir (tree->selected_ptr->name))
719 return 0;
720 /* FIXME
721 mkdir_cmd (tree);
723 tree_rescan_cmd (tree);
724 chdir (old_dir);
725 return 1;
727 #endif
729 static void
730 tree_rmdir_cmd (WTree *tree)
732 char old_dir [MC_MAXPATHLEN];
733 long count = 0;
734 double bytes = 0;
735 FileOpContext *ctx;
737 if (tree->selected_ptr){
738 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
739 return;
740 if (mc_chdir (PATH_SEP_STR))
741 return;
742 if (confirm_delete){
743 char *buf;
744 int result;
746 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
747 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
748 g_free (buf);
749 if (result != 0){
750 return;
754 ctx = file_op_context_new ();
755 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
756 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
757 tree_forget_cmd (tree);
758 file_op_context_destroy (ctx);
759 mc_chdir (old_dir);
760 return;
761 } else
762 return;
765 static void set_navig_label (Dlg_head *h);
767 static void
768 tree_toggle_navig (Dlg_head *h)
770 tree_navigation_flag = 1 - tree_navigation_flag;
771 set_navig_label (h);
774 void
775 set_navig_label (Dlg_head *h)
777 define_label_data (h, (Widget *)tree,
778 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
779 (void (*)(void *))tree_toggle_navig, h);
782 static void
783 move_down (WTree *tree)
785 tree_move_forward (tree, 1);
786 show_tree (tree);
787 maybe_chdir (tree);
790 static void
791 move_up (WTree *tree)
793 tree_move_backward (tree, 1);
794 show_tree (tree);
795 maybe_chdir (tree);
798 static void
799 move_home (WTree *tree)
801 tree_move_to_top (tree);
802 show_tree (tree);
803 maybe_chdir (tree);
806 static void
807 move_end (WTree *tree)
809 tree_move_to_bottom (tree);
810 show_tree (tree);
811 maybe_chdir (tree);
814 static int
815 move_left (WTree *tree)
817 int v;
819 if (tree_navigation_flag){
820 v = tree_move_to_parent (tree);
821 show_tree (tree);
822 maybe_chdir (tree);
823 return v;
825 return 0;
828 static int
829 move_right (WTree *tree)
831 if (tree_navigation_flag){
832 tree_move_to_child (tree);
833 show_tree (tree);
834 maybe_chdir (tree);
835 return 1;
837 return 0;
840 static void
841 move_prevp (WTree *tree)
843 tree_move_backward (tree, tlines (tree) - 1);
844 show_tree (tree);
845 maybe_chdir (tree);
848 static void
849 move_nextp (WTree *tree)
851 tree_move_forward (tree, tlines (tree) - 1);
852 show_tree (tree);
853 maybe_chdir (tree);
856 static void
857 chdir_sel (WTree *tree)
859 if (!tree->is_panel){
860 tree->done = 1;
861 return;
863 change_panel ();
864 if (do_cd (tree->selected_ptr->name, cd_exact)){
865 paint_panel (cpanel);
866 select_item (cpanel);
867 } else {
868 message (1, MSG_ERROR, _(" Can't chdir to \"%s\" \n %s "),
869 tree->selected_ptr->name, unix_error_string (errno));
871 change_panel ();
872 show_tree (tree);
873 return;
876 static void
877 tree_start_search (WTree *tree)
879 int i;
881 if (tree->searching){
883 if (tree->selected_ptr == tree->store->tree_last)
884 tree_move_to_top(tree);
885 else {
886 /* set navigation mode temporarily to 'Static' because in
887 * dynamic navigation mode tree_move_forward will not move
888 * to a lower sublevel if necessary (sequent searches must
889 * start with the directory followed the last found directory)
891 i = tree_navigation_flag;
892 tree_navigation_flag = 0;
893 tree_move_forward (tree, 1);
894 tree_navigation_flag = i;
896 tree_do_search (tree, 0);
898 else {
899 tree->searching = 1;
900 tree->search_buffer[0] = 0;
904 static key_map tree_keymap [] = {
905 { XCTRL('n'), move_down },
906 { XCTRL('p'), move_up },
907 { KEY_DOWN, move_down },
908 { KEY_UP, move_up },
909 { '\n', chdir_sel },
910 { KEY_ENTER, chdir_sel },
911 { KEY_HOME, move_home },
912 { KEY_C1, move_end },
913 { KEY_END, move_end },
914 { KEY_A1, move_home },
915 { KEY_NPAGE, move_nextp },
916 { KEY_PPAGE, move_prevp },
917 { XCTRL('v'), move_nextp },
918 { ALT('v'), move_prevp },
919 { XCTRL('p'), move_up },
920 { XCTRL('p'), move_down },
921 { XCTRL('s'), tree_start_search },
922 { ALT('s'), tree_start_search },
923 { XCTRL('r'), tree_rescan_cmd },
924 { KEY_DC, tree_rmdir_cmd },
925 { 0, 0 }
928 static inline int
929 tree_key (WTree *tree, int key)
931 int i;
933 for (i = 0; tree_keymap [i].key_code; i++){
934 if (key == tree_keymap [i].key_code){
935 if (tree_keymap [i].fn != tree_start_search)
936 tree->searching = 0;
937 (*tree_keymap [i].fn)(tree);
938 show_tree (tree);
939 return 1;
943 /* We do not want to use them if we do not need to */
944 /* Input line may want to take the motion key event */
945 if (key == KEY_LEFT)
946 return move_left (tree);
948 if (key == KEY_RIGHT)
949 return move_right (tree);
951 if (is_abort_char (key)) {
952 if (tree->is_panel) {
953 tree->searching = 0;
954 show_tree (tree);
955 return 1; /* eat abort char */
957 return 0; /* modal tree dialog: let upper layer see the
958 abort character and close the dialog */
961 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
962 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
963 if (tree->searching){
964 tree_do_search (tree, key);
965 show_tree (tree);
966 return 1;
969 if (!command_prompt) {
970 tree_start_search (tree);
971 tree_do_search (tree, key);
972 return 1;
974 return tree->is_panel;
977 return 0;
980 static void
981 tree_frame (Dlg_head *h, WTree *tree)
983 attrset (NORMAL_COLOR);
984 widget_erase ((Widget*) tree);
985 if (tree->is_panel)
986 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
987 tree->widget.cols);
989 if (show_mini_info && tree->is_panel){
990 widget_move (tree, tlines (tree) + 1, 1);
991 hline (ACS_HLINE, tree->widget.cols - 2);
996 static int
997 tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
999 switch (msg){
1000 case WIDGET_DRAW:
1001 tree_frame (h, tree);
1002 show_tree (tree);
1003 return 1;
1005 case WIDGET_KEY:
1006 return tree_key (tree, par);
1008 case WIDGET_FOCUS:
1009 tree->active = 1;
1010 define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
1011 define_label_data (h, (Widget *)tree,
1012 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
1013 define_label_data (h, (Widget *)tree,
1014 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
1015 define_label_data (h, (Widget *)tree,
1016 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
1017 define_label_data (h, (Widget *)tree,
1018 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1019 #if 0
1020 /* FIXME: mkdir is currently defunct */
1021 define_label_data (h, (Widget *)tree,
1022 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1023 #else
1024 define_label (h, (Widget *)tree, 7, "", 0);
1025 #endif
1026 define_label_data (h, (Widget *)tree,
1027 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
1028 set_navig_label (h);
1029 redraw_labels (h, (Widget *)tree);
1032 /* FIXME: Should find a better way of only displaying the
1033 currently selected item */
1034 show_tree (tree);
1035 return 1;
1037 /* FIXME: Should find a better way of changing the color of the
1038 selected item */
1039 case WIDGET_UNFOCUS:
1040 tree->active = 0;
1041 show_tree (tree);
1042 return 1;
1044 return default_proc (h, msg, par);
1047 WTree *
1048 tree_new (int is_panel, int y, int x, int lines, int cols)
1050 WTree *tree = g_new (WTree, 1);
1052 init_widget (&tree->widget, y, x, lines, cols, tcallback,
1053 (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
1054 tree->is_panel = is_panel;
1055 tree->selected_ptr = 0;
1057 tree->store = tree_store_get ();
1058 tree_store_add_entry_remove_hook (remove_callback, tree);
1059 tree->tree_shown = 0;
1060 tree->search_buffer [0] = 0;
1061 tree->topdiff = tree->widget.lines / 2;
1062 tree->searching = 0;
1063 tree->done = 0;
1064 tree->active = 0;
1066 /* We do not want to keep the cursor */
1067 widget_want_cursor (tree->widget, 0);
1068 load_tree (tree);
1069 return tree;