Just a little correction at the it.po file.
[midnight-commander.git] / src / tree.c
blob12ba92733337bfed31de63398eedd8f48125c04c
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 "wtools.h" /* message() */
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 "help.h"
46 #include "key.h" /* For mi_getch() */
47 #include "tree.h"
48 #include "cmd.h"
50 extern int command_prompt;
52 /* Use the color of the parent widget for the unselected entries */
53 #define TREE_NORMALC NORMALC
55 /* Specifies the display mode: 1d or 2d */
56 static int tree_navigation_flag;
58 struct WTree {
59 Widget widget;
60 TreeStore *store;
61 tree_entry *selected_ptr; /* The selected directory */
62 char search_buffer[256]; /* Current search string */
63 tree_entry **tree_shown; /* Entries currently on screen */
64 int is_panel; /* panel or plain widget flag */
65 int active; /* if it's currently selected */
66 int searching; /* Are we on searching mode? */
67 int topdiff; /* The difference between the topmost
68 shown and the selected */
71 /* Forwards */
72 static void save_tree (WTree *tree);
73 static void tree_rescan_cmd (WTree *tree);
74 static int tree_callback (WTree *tree, int msg, int par);
76 static tree_entry *back_ptr (tree_entry *ptr, int *count)
78 int i = 0;
80 while (ptr && ptr->prev && i < *count){
81 ptr = ptr->prev;
82 i ++;
84 *count = i;
85 return ptr;
88 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
90 int i = 0;
92 while (ptr && ptr->next && i < *count){
93 ptr = ptr->next;
94 i ++;
96 *count = i;
97 return ptr;
100 #if 0
101 /* Add a directory to the list of directories */
102 static tree_entry *tree_add_entry (WTree *tree, char *name)
104 if (!tree)
105 return 0;
107 return tree_store_add_entry (name);
110 /* Append a directory to the list of directories */
111 static tree_entry *tree_append_entry (WTree *tree, char *name)
113 tree_entry *current, *new;
114 int i, len;
115 int submask = 0;
117 /* We assume the directory is not yet in the list */
119 new = g_new (tree_entry, 1);
120 if (!tree->store->tree_first){
121 /* Empty list */
122 tree->store->tree_first = new;
123 new->prev = NULL;
124 } else {
125 tree->tree_last->next = new;
126 new->prev = tree->tree_last;
128 new->next = NULL;
129 tree->store->tree_last = new;
131 /* Calculate attributes */
132 new->name = g_strdup (name);
133 len = strlen (new->name);
134 new->sublevel = 0;
135 for (i = 0; i < len; i++)
136 if (new->name [i] == PATH_SEP){
137 new->sublevel++;
138 new->subname = new->name + i + 1;
140 submask = 1 << new->sublevel;
141 submask &= (2 << new->sublevel) - 1;
142 new->submask = submask;
143 new->mark = 0;
145 /* Correct the submasks of the previous entries */
146 current = new->prev;
147 while (current && current->sublevel > new->sublevel){
148 current->submask |= 1 << new->sublevel;
149 current = current->prev;
152 /* The entry has now been appended */
153 return new;
155 #endif
157 static void
158 remove_callback (tree_entry *entry, void *data)
160 WTree *tree = data;
162 if (tree->selected_ptr == entry){
163 if (tree->selected_ptr->next)
164 tree->selected_ptr = tree->selected_ptr->next;
165 else
166 tree->selected_ptr = tree->selected_ptr->prev;
170 static void tree_remove_entry (WTree *tree, char *name)
172 tree_store_remove_entry (name);
175 static void tree_destroy (WTree *tree)
177 tree_store_remove_entry_remove_hook (remove_callback);
178 save_tree (tree);
180 if (tree->tree_shown){
181 g_free (tree->tree_shown);
182 tree->tree_shown = 0;
184 tree->selected_ptr = NULL;
187 /* Loads the .mc.tree file */
188 static void load_tree (WTree *tree)
190 tree_store_load ();
192 tree->selected_ptr = tree->store->tree_first;
193 tree_chdir (tree, home_dir);
196 /* Save the .mc.tree file */
197 static void save_tree (WTree *tree)
199 int error;
201 error = tree_store_save ();
203 if (error){
204 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
205 unix_error_string (error));
206 return;
210 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
212 Dlg_head *h = tree->widget.parent;
213 int line;
215 /* Show mini info */
216 if (tree->is_panel){
217 if (!show_mini_info)
218 return;
219 line = tree_lines+2;
220 } else
221 line = tree_lines+1;
223 widget_move (&tree->widget, line, 1);
224 hline (' ', tree_cols);
225 widget_move (&tree->widget, line, 1);
227 if (tree->searching){
228 /* Show search string */
229 attrset (TREE_NORMALC);
230 attrset (FOCUSC);
231 addch (PATH_SEP);
233 addstr (name_trunc (tree->search_buffer, tree_cols-2));
234 addch (' ');
235 attrset (FOCUSC);
236 } else {
237 /* Show full name of selected directory */
238 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
242 static void show_tree (WTree *tree)
244 Dlg_head *h = tree->widget.parent;
245 tree_entry *current;
246 int i, j, topsublevel;
247 int x, y;
248 int tree_lines, tree_cols;
250 /* Initialize */
251 x = y = 0;
252 tree_lines = tlines (tree);
253 tree_cols = tree->widget.cols;
255 attrset (TREE_NORMALC);
256 widget_move ((Widget*)tree, y, x);
257 if (tree->is_panel){
258 tree_cols -= 2;
259 x = y = 1;
262 if (tree->tree_shown)
263 g_free (tree->tree_shown);
264 tree->tree_shown = g_new (tree_entry*, tree_lines);
266 for (i = 0; i < tree_lines; i++)
267 tree->tree_shown [i] = NULL;
268 if (tree->store->tree_first)
269 topsublevel = tree->store->tree_first->sublevel;
270 else
271 topsublevel = 0;
272 if (!tree->selected_ptr){
273 tree->selected_ptr = tree->store->tree_first;
274 tree->topdiff = 0;
276 current = tree->selected_ptr;
278 /* Calculate the directory which is to be shown on the topmost line */
279 if (tree_navigation_flag){
280 i = 0;
281 while (current->prev && i < tree->topdiff){
282 current = current->prev;
283 if (current->sublevel < tree->selected_ptr->sublevel){
284 if (strncmp (current->name, tree->selected_ptr->name,
285 strlen (current->name)) == 0)
286 i++;
287 } else if (current->sublevel == tree->selected_ptr->sublevel){
288 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
289 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
290 i++;
291 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
292 && strlen (tree->selected_ptr->name) > 1){
293 if (strncmp (current->name, tree->selected_ptr->name,
294 strlen (tree->selected_ptr->name)) == 0)
295 i++;
298 tree->topdiff = i;
299 } else
300 current = back_ptr (current, &tree->topdiff);
302 /* Loop for every line */
303 for (i = 0; i < tree_lines; i++){
304 /* Move to the beginning of the line */
305 widget_move (&tree->widget, y+i, x);
307 hline (' ', tree_cols);
308 widget_move (&tree->widget, y+i, x);
310 if (!current)
311 continue;
313 tree->tree_shown [i] = current;
314 if (current->sublevel == topsublevel){
316 /* Top level directory */
317 if (tree->active && current == tree->selected_ptr) {
318 if (!use_colors && !tree->is_panel)
319 attrset (MARKED_COLOR);
320 else
321 attrset (SELECTED_COLOR);
324 /* Show full name */
325 addstr (name_trunc (current->name, tree_cols - 6));
326 } else{
327 /* Sub level directory */
329 acs ();
330 /* Output branch parts */
331 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
332 if (tree_cols - 8 - 3 * j < 9)
333 break;
334 addch (' ');
335 if (current->submask & (1 << (j + topsublevel + 1)))
336 addch (ACS_VLINE);
337 else
338 addch (' ');
339 addch (' ');
341 addch (' '); j++;
342 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
343 addch (ACS_LLCORNER);
344 else
345 addch (ACS_LTEE);
346 addch (ACS_HLINE);
347 noacs ();
349 if (tree->active && current == tree->selected_ptr) {
350 /* Selected directory -> change color */
351 if (!use_colors && !tree->is_panel)
352 attrset (MARKED_COLOR);
353 else
354 attrset (SELECTED_COLOR);
357 /* Show sub-name */
358 addch (' ');
359 addstr (name_trunc (current->subname,
360 tree_cols - 2 - 4 - 3 * j));
362 addch (' ');
364 /* Return to normal color */
365 attrset (TREE_NORMALC);
367 /* Calculate the next value for current */
368 current = current->next;
369 if (tree_navigation_flag){
370 while (current){
371 if (current->sublevel < tree->selected_ptr->sublevel){
372 if (strncmp (current->name, tree->selected_ptr->name,
373 strlen (current->name)) == 0)
374 break;
375 } else if (current->sublevel == tree->selected_ptr->sublevel){
376 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
377 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
378 break;
379 } else if (current->sublevel == tree->selected_ptr->sublevel+1
380 && strlen (tree->selected_ptr->name) > 1){
381 if (strncmp (current->name, tree->selected_ptr->name,
382 strlen (tree->selected_ptr->name)) == 0)
383 break;
385 current = current->next;
389 tree_show_mini_info (tree, tree_lines, tree_cols);
392 static void check_focus (WTree *tree)
394 if (tree->topdiff < 3)
395 tree->topdiff = 3;
396 else if (tree->topdiff >= tlines (tree) - 3)
397 tree->topdiff = tlines (tree) - 3 - 1;
400 static void tree_move_backward (WTree *tree, int i)
402 tree_entry *current;
403 int j = 0;
405 if (tree_navigation_flag){
406 current = tree->selected_ptr;
407 while (j < i && current->prev
408 && current->prev->sublevel >= tree->selected_ptr->sublevel){
409 current = current->prev;
410 if (current->sublevel == tree->selected_ptr->sublevel){
411 tree->selected_ptr = current;
412 j ++;
415 i = j;
416 } else
417 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
418 tree->topdiff -= i;
419 check_focus (tree);
422 static void tree_move_forward (WTree *tree, int i)
424 tree_entry *current;
425 int j = 0;
427 if (tree_navigation_flag){
428 current = tree->selected_ptr;
429 while (j < i && current->next
430 && current->next->sublevel >= tree->selected_ptr->sublevel){
431 current = current->next;
432 if (current->sublevel == tree->selected_ptr->sublevel){
433 tree->selected_ptr = current;
434 j ++;
437 i = j;
438 } else
439 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
440 tree->topdiff += i;
441 check_focus (tree);
444 static void tree_move_to_child (WTree *tree)
446 tree_entry *current;
448 /* Do we have a starting point? */
449 if (!tree->selected_ptr)
450 return;
451 /* Take the next entry */
452 current = tree->selected_ptr->next;
453 /* Is it the child of the selected entry */
454 if (current && current->sublevel > tree->selected_ptr->sublevel){
455 /* Yes -> select this entry */
456 tree->selected_ptr = current;
457 tree->topdiff++;
458 check_focus (tree);
459 } else {
460 /* No -> rescan and try again */
461 tree_rescan_cmd (tree);
462 current = tree->selected_ptr->next;
463 if (current && current->sublevel > tree->selected_ptr->sublevel){
464 tree->selected_ptr = current;
465 tree->topdiff++;
466 check_focus (tree);
471 static int tree_move_to_parent (WTree *tree)
473 tree_entry *current;
474 tree_entry *old;
476 if (!tree->selected_ptr)
477 return 0;
478 old = tree->selected_ptr;
479 current = tree->selected_ptr->prev;
480 while (current && current->sublevel >= tree->selected_ptr->sublevel){
481 current = current->prev;
482 tree->topdiff--;
484 if (!current)
485 current = tree->store->tree_first;
486 tree->selected_ptr = current;
487 check_focus (tree);
488 return tree->selected_ptr != old;
491 static void tree_move_to_top (WTree *tree)
493 tree->selected_ptr = tree->store->tree_first;
494 tree->topdiff = 0;
497 static void tree_move_to_bottom (WTree *tree)
499 tree->selected_ptr = tree->store->tree_last;
500 tree->topdiff = tlines (tree) - 3 - 1;
503 void tree_chdir (WTree *tree, char *dir)
505 tree_entry *current;
507 current = tree_store_whereis (dir);
508 if (current){
509 tree->selected_ptr = current;
510 check_focus (tree);
514 void
515 sync_tree (char *path)
517 tree_chdir (the_tree, path);
520 /* Handle mouse click */
521 static void tree_event (WTree *tree, int y)
523 if (tree->tree_shown [y]){
524 tree->selected_ptr = tree->tree_shown [y];
525 tree->topdiff = y;
527 show_tree (tree);
530 static void chdir_sel (WTree *tree);
532 static void maybe_chdir (WTree *tree)
534 if (!(xtree_mode && tree->is_panel))
535 return;
536 if (is_idle ())
537 chdir_sel (tree);
540 /* Mouse callback */
541 static int event_callback (Gpm_Event *event, WTree *tree)
543 if (!(event->type & GPM_UP))
544 return MOU_NORMAL;
546 if (tree->is_panel)
547 event->y--;
549 event->y--;
551 if (!tree->active)
552 change_panel ();
554 if (event->y < 0){
555 tree_move_backward (tree, tlines (tree) - 1);
556 show_tree (tree);
558 else if (event->y >= tlines (tree)){
559 tree_move_forward (tree, tlines (tree) - 1);
560 show_tree (tree);
561 } else {
562 tree_event (tree, event->y);
563 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
564 chdir_sel (tree);
567 return MOU_NORMAL;
570 /* Search tree for text */
571 static int search_tree (WTree *tree, char *text)
573 tree_entry *current;
574 int len;
575 int wrapped = 0;
576 int found = 0;
578 len = strlen (text);
579 current = tree->selected_ptr;
580 found = 0;
581 while (!wrapped || current != tree->selected_ptr){
582 if (strncmp (current->subname, text, len) == 0){
583 tree->selected_ptr = current;
584 found = 1;
585 break;
587 current = current->next;
588 if (!current){
589 current = tree->store->tree_first;
590 wrapped = 1;
592 tree->topdiff++;
594 check_focus (tree);
595 return found;
598 static void tree_do_search (WTree *tree, int key)
600 int l;
602 l = strlen (tree->search_buffer);
603 if (l && (key == KEY_BACKSPACE))
604 tree->search_buffer [--l] = 0;
605 else {
606 if (key && l < sizeof (tree->search_buffer)){
607 tree->search_buffer [l] = key;
608 tree->search_buffer [l+1] = 0;
609 l++;
613 if (!search_tree (tree, tree->search_buffer))
614 tree->search_buffer [--l] = 0;
616 show_tree (tree);
617 maybe_chdir (tree);
620 static void tree_rescan_cmd (WTree *tree)
622 char old_dir [MC_MAXPATHLEN];
624 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
625 mc_chdir (tree->selected_ptr->name))
626 return;
628 tree_store_rescan (tree->selected_ptr->name);
629 mc_chdir (old_dir);
632 static int tree_forget_cmd (WTree *tree)
634 if (tree->selected_ptr)
635 tree_remove_entry (tree, tree->selected_ptr->name);
636 return 1;
639 static void tree_copy (WTree *tree, char *default_dest)
641 char *dest;
642 off_t count = 0;
643 double bytes = 0;
644 FileOpContext *ctx;
646 if (!tree->selected_ptr)
647 return;
648 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
649 name_trunc (tree->selected_ptr->name, 50));
650 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
652 if (!dest)
653 return;
655 if (!*dest){
656 g_free (dest);
657 return;
660 ctx = file_op_context_new ();
661 file_op_context_create_ui (ctx, OP_COPY, FALSE);
662 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
663 file_op_context_destroy (ctx);
665 g_free (dest);
668 static void tree_help_cmd (void)
670 interactive_display (NULL, "[Directory Tree]");
673 static int tree_copy_cmd (WTree *tree)
675 tree_copy (tree, "");
676 return 1;
679 static void tree_move (WTree *tree, char *default_dest)
681 char *dest;
682 struct stat buf;
683 double bytes = 0;
684 off_t count = 0;
685 FileOpContext *ctx;
687 if (!tree->selected_ptr)
688 return;
689 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
690 name_trunc (tree->selected_ptr->name, 50));
691 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
692 if (!dest)
693 return;
694 if (!*dest){
695 g_free (dest);
696 return;
698 if (stat (dest, &buf)){
699 message (1, MSG_ERROR, _(" Cannot stat the destination \n %s "),
700 unix_error_string (errno));
701 g_free (dest);
702 return;
704 if (!S_ISDIR (buf.st_mode)){
705 file_error (_(" Destination \"%s\" must be a directory \n %s "),
706 dest);
707 g_free (dest);
708 return;
711 ctx = file_op_context_new ();
712 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
713 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
714 file_op_context_destroy (ctx);
716 g_free (dest);
719 static int
720 tree_move_cmd (WTree *tree)
722 tree_move (tree, "");
723 return 1;
726 #if 0
727 static int
728 tree_mkdir_cmd (WTree *tree)
730 char old_dir [MC_MAXPATHLEN];
732 if (!tree->selected_ptr)
733 return 0;
734 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
735 return 0;
736 if (chdir (tree->selected_ptr->name))
737 return 0;
738 /* FIXME
739 mkdir_cmd (tree);
741 tree_rescan_cmd (tree);
742 chdir (old_dir);
743 return 1;
745 #endif
747 static void
748 tree_rmdir_cmd (WTree *tree)
750 char old_dir [MC_MAXPATHLEN];
751 off_t count = 0;
752 double bytes = 0;
753 FileOpContext *ctx;
755 if (tree->selected_ptr){
756 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
757 return;
758 if (mc_chdir (PATH_SEP_STR))
759 return;
760 if (confirm_delete){
761 char *buf;
762 int result;
764 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
765 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
766 g_free (buf);
767 if (result != 0){
768 return;
772 ctx = file_op_context_new ();
773 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
774 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
775 tree_forget_cmd (tree);
776 file_op_context_destroy (ctx);
777 mc_chdir (old_dir);
778 return;
779 } else
780 return;
783 static void set_navig_label (WTree *tree);
785 static void
786 tree_toggle_navig (WTree *tree)
788 tree_navigation_flag = 1 - tree_navigation_flag;
789 set_navig_label (tree);
792 static void
793 set_navig_label (WTree *tree)
795 define_label_data (tree->widget.parent, 4,
796 tree_navigation_flag ? _("Static") : _("Dynamc"),
797 (buttonbarfn) tree_toggle_navig, tree);
800 static void
801 move_down (WTree *tree)
803 tree_move_forward (tree, 1);
804 show_tree (tree);
805 maybe_chdir (tree);
808 static void
809 move_up (WTree *tree)
811 tree_move_backward (tree, 1);
812 show_tree (tree);
813 maybe_chdir (tree);
816 static void
817 move_home (WTree *tree)
819 tree_move_to_top (tree);
820 show_tree (tree);
821 maybe_chdir (tree);
824 static void
825 move_end (WTree *tree)
827 tree_move_to_bottom (tree);
828 show_tree (tree);
829 maybe_chdir (tree);
832 static int
833 move_left (WTree *tree)
835 int v;
837 if (tree_navigation_flag){
838 v = tree_move_to_parent (tree);
839 show_tree (tree);
840 maybe_chdir (tree);
841 return v;
843 return 0;
846 static int
847 move_right (WTree *tree)
849 if (tree_navigation_flag){
850 tree_move_to_child (tree);
851 show_tree (tree);
852 maybe_chdir (tree);
853 return 1;
855 return 0;
858 static void
859 move_prevp (WTree *tree)
861 tree_move_backward (tree, tlines (tree) - 1);
862 show_tree (tree);
863 maybe_chdir (tree);
866 static void
867 move_nextp (WTree *tree)
869 tree_move_forward (tree, tlines (tree) - 1);
870 show_tree (tree);
871 maybe_chdir (tree);
874 static void
875 chdir_sel (WTree *tree)
877 if (!tree->is_panel) {
878 return;
880 change_panel ();
881 if (do_cd (tree->selected_ptr->name, cd_exact)) {
882 paint_panel (cpanel);
883 select_item (cpanel);
884 } else {
885 message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
886 tree->selected_ptr->name, unix_error_string (errno));
888 change_panel ();
889 show_tree (tree);
890 return;
893 static void
894 tree_start_search (WTree *tree)
896 int i;
898 if (tree->searching){
900 if (tree->selected_ptr == tree->store->tree_last)
901 tree_move_to_top(tree);
902 else {
903 /* set navigation mode temporarily to 'Static' because in
904 * dynamic navigation mode tree_move_forward will not move
905 * to a lower sublevel if necessary (sequent searches must
906 * start with the directory followed the last found directory)
908 i = tree_navigation_flag;
909 tree_navigation_flag = 0;
910 tree_move_forward (tree, 1);
911 tree_navigation_flag = i;
913 tree_do_search (tree, 0);
915 else {
916 tree->searching = 1;
917 tree->search_buffer[0] = 0;
921 static const key_map tree_keymap [] = {
922 { XCTRL('n'), move_down },
923 { XCTRL('p'), move_up },
924 { KEY_DOWN, move_down },
925 { KEY_UP, move_up },
926 { '\n', chdir_sel },
927 { KEY_ENTER, chdir_sel },
928 { KEY_HOME, move_home },
929 { KEY_C1, move_end },
930 { KEY_END, move_end },
931 { KEY_A1, move_home },
932 { KEY_NPAGE, move_nextp },
933 { KEY_PPAGE, move_prevp },
934 { XCTRL('v'), move_nextp },
935 { ALT('v'), move_prevp },
936 { XCTRL('p'), move_up },
937 { XCTRL('p'), move_down },
938 { XCTRL('s'), tree_start_search },
939 { ALT('s'), tree_start_search },
940 { XCTRL('r'), tree_rescan_cmd },
941 { KEY_DC, tree_rmdir_cmd },
942 { 0, 0 }
945 static inline int
946 tree_key (WTree *tree, int key)
948 int i;
950 for (i = 0; tree_keymap [i].key_code; i++){
951 if (key == tree_keymap [i].key_code){
952 if (tree_keymap [i].fn != tree_start_search)
953 tree->searching = 0;
954 (*tree_keymap [i].fn)(tree);
955 show_tree (tree);
956 return 1;
960 /* We do not want to use them if we do not need to */
961 /* Input line may want to take the motion key event */
962 if (key == KEY_LEFT)
963 return move_left (tree);
965 if (key == KEY_RIGHT)
966 return move_right (tree);
968 if (is_abort_char (key)) {
969 if (tree->is_panel) {
970 tree->searching = 0;
971 show_tree (tree);
972 return 1; /* eat abort char */
974 return 0; /* modal tree dialog: let upper layer see the
975 abort character and close the dialog */
978 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
979 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
980 if (tree->searching){
981 tree_do_search (tree, key);
982 show_tree (tree);
983 return 1;
986 if (!command_prompt) {
987 tree_start_search (tree);
988 tree_do_search (tree, key);
989 return 1;
991 return tree->is_panel;
994 return 0;
997 static void
998 tree_frame (Dlg_head *h, WTree *tree)
1000 attrset (NORMAL_COLOR);
1001 widget_erase ((Widget*) tree);
1002 if (tree->is_panel)
1003 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
1004 tree->widget.cols);
1006 if (show_mini_info && tree->is_panel){
1007 widget_move (tree, tlines (tree) + 1, 1);
1008 hline (ACS_HLINE, tree->widget.cols - 2);
1013 static int
1014 tree_callback (WTree *tree, int msg, int par)
1016 Dlg_head *h = tree->widget.parent;
1018 switch (msg) {
1019 case WIDGET_DRAW:
1020 tree_frame (h, tree);
1021 show_tree (tree);
1022 return 1;
1024 case WIDGET_KEY:
1025 return tree_key (tree, par);
1027 case WIDGET_FOCUS:
1028 tree->active = 1;
1029 define_label (h, 1, _("Help"), (voidfn) tree_help_cmd);
1030 define_label_data (h, 2, _("Rescan"),
1031 (buttonbarfn) tree_rescan_cmd, tree);
1032 define_label_data (h, 3, _("Forget"),
1033 (buttonbarfn) tree_forget_cmd, tree);
1034 define_label_data (h, 5, _("Copy"), (buttonbarfn) tree_copy_cmd,
1035 tree);
1036 define_label_data (h, 6, _("RenMov"), (buttonbarfn) tree_move_cmd,
1037 tree);
1038 #if 0
1039 /* FIXME: mkdir is currently defunct */
1040 define_label_data (h, 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd,
1041 tree);
1042 #else
1043 define_label (h, 7, "", 0);
1044 #endif
1045 define_label_data (h, 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd,
1046 tree);
1047 set_navig_label (tree);
1048 redraw_labels (h);
1051 /* FIXME: Should find a better way of only displaying the
1052 currently selected item */
1053 show_tree (tree);
1054 return 1;
1056 /* FIXME: Should find a better way of changing the color of the
1057 selected item */
1058 case WIDGET_UNFOCUS:
1059 tree->active = 0;
1060 show_tree (tree);
1061 return 1;
1063 return default_proc (msg, par);
1066 WTree *
1067 tree_new (int is_panel, int y, int x, int lines, int cols)
1069 WTree *tree = g_new (WTree, 1);
1071 init_widget (&tree->widget, y, x, lines, cols,
1072 (callback_fn) tree_callback, (destroy_fn) tree_destroy,
1073 (mouse_h) event_callback, NULL);
1074 tree->is_panel = is_panel;
1075 tree->selected_ptr = 0;
1077 tree->store = tree_store_get ();
1078 tree_store_add_entry_remove_hook (remove_callback, tree);
1079 tree->tree_shown = 0;
1080 tree->search_buffer[0] = 0;
1081 tree->topdiff = tree->widget.lines / 2;
1082 tree->searching = 0;
1083 tree->active = 0;
1085 /* We do not want to keep the cursor */
1086 widget_want_cursor (tree->widget, 0);
1087 load_tree (tree);
1088 return tree;
1091 /* Return name of the currently selected entry */
1092 char *
1093 tree_selected_name (WTree *tree)
1095 return tree->selected_ptr->name;