Clean menu -- made to use standart GNOME menu entries
[midnight-commander.git] / src / tree.c
blob98b1cb7ad3095396da784ab8394e10d9d26faa8d
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., 675 Mass Ave, Cambridge, MA 02139, 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);
167 tree_store_destroy ();
169 if (tree->tree_shown){
170 g_free (tree->tree_shown);
171 tree->tree_shown = 0;
173 tree->selected_ptr = NULL;
176 /* Loads the .mc.tree file */
177 void load_tree (WTree *tree)
179 char *filename;
180 int v;
182 filename = concat_dir_and_file (home_dir, MC_TREE);
183 v = tree_store_load (filename);
184 g_free (filename);
186 tree->selected_ptr = tree->store->tree_first;
188 tree_chdir (tree, home_dir);
191 /* Save the .mc.tree file */
192 void save_tree (WTree *tree)
194 int error;
195 char *filename;
197 filename = concat_dir_and_file (home_dir, MC_TREE);
198 error = tree_store_save (filename);
199 g_free (filename);
201 if (error){
202 fprintf (stderr, _("Can't open the %s file for writing:\n%s\n"), MC_TREE,
203 unix_error_string (error));
204 return;
208 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
210 Dlg_head *h = tree->widget.parent;
211 int line;
213 /* Show mini info */
214 if (tree->is_panel){
215 if (!show_mini_info)
216 return;
217 line = tree_lines+2;
218 } else
219 line = tree_lines+1;
221 widget_move (&tree->widget, line, 1);
222 hline (' ', tree_cols);
223 widget_move (&tree->widget, line, 1);
225 if (tree->searching){
226 /* Show search string */
227 attrset (TREE_NORMALC);
228 attrset (FOCUSC);
229 addch (PATH_SEP);
231 addstr (name_trunc (tree->search_buffer, tree_cols-2));
232 addch (' ');
233 attrset (FOCUSC);
234 } else {
235 /* Show full name of selected directory */
236 addstr (name_trunc (tree->selected_ptr->name, tree_cols));
240 void show_tree (WTree *tree)
242 Dlg_head *h = tree->widget.parent;
243 tree_entry *current;
244 int i, j, topsublevel;
245 int x, y;
246 int tree_lines, tree_cols;
248 /* Initialize */
249 x = y = 0;
250 tree_lines = tlines (tree);
251 tree_cols = tree->widget.cols;
253 attrset (TREE_NORMALC);
254 widget_move ((Widget*)tree, y, x);
255 if (tree->is_panel){
256 tree_cols -= 2;
257 x = y = 1;
260 if (tree->tree_shown)
261 g_free (tree->tree_shown);
262 tree->tree_shown = g_new (tree_entry*, tree_lines);
264 for (i = 0; i < tree_lines; i++)
265 tree->tree_shown [i] = NULL;
266 if (tree->store->tree_first)
267 topsublevel = tree->store->tree_first->sublevel;
268 else
269 topsublevel = 0;
270 if (!tree->selected_ptr){
271 tree->selected_ptr = tree->store->tree_first;
272 tree->topdiff = 0;
274 current = tree->selected_ptr;
276 /* Calculate the directory which is to be shown on the topmost line */
277 if (tree_navigation_flag){
278 i = 0;
279 while (current->prev && i < tree->topdiff){
280 current = current->prev;
281 if (current->sublevel < tree->selected_ptr->sublevel){
282 if (strncmp (current->name, tree->selected_ptr->name,
283 strlen (current->name)) == 0)
284 i++;
285 } else if (current->sublevel == tree->selected_ptr->sublevel){
286 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
287 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
288 i++;
289 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
290 && strlen (tree->selected_ptr->name) > 1){
291 if (strncmp (current->name, tree->selected_ptr->name,
292 strlen (tree->selected_ptr->name)) == 0)
293 i++;
296 tree->topdiff = i;
297 } else
298 current = back_ptr (current, &tree->topdiff);
300 /* Loop for every line */
301 for (i = 0; i < tree_lines; i++){
302 /* Move to the beginning of the line */
303 widget_move (&tree->widget, y+i, x);
305 hline (' ', tree_cols);
306 widget_move (&tree->widget, y+i, x);
308 if (!current)
309 continue;
311 tree->tree_shown [i] = current;
312 if (current->sublevel == topsublevel){
314 /* Top level directory */
315 if (tree->active && current == tree->selected_ptr) {
316 if (!use_colors && !tree->is_panel)
317 attrset (MARKED_COLOR);
318 else
319 attrset (SELECTED_COLOR);
322 /* Show full name */
323 addstr (name_trunc (current->name, tree_cols - 6));
324 } else{
325 /* Sub level directory */
327 acs ();
328 /* Output branch parts */
329 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
330 if (tree_cols - 8 - 3 * j < 9)
331 break;
332 addch (' ');
333 if (current->submask & (1 << (j + topsublevel + 1)))
334 addch (ACS_VLINE);
335 else
336 addch (' ');
337 addch (' ');
339 addch (' '); j++;
340 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
341 addch (ACS_LLCORNER);
342 else
343 addch (ACS_LTEE);
344 addch (ACS_HLINE);
345 noacs ();
347 if (tree->active && current == tree->selected_ptr) {
348 /* Selected directory -> change color */
349 if (!use_colors && !tree->is_panel)
350 attrset (MARKED_COLOR);
351 else
352 attrset (SELECTED_COLOR);
355 /* Show sub-name */
356 addch (' ');
357 addstr (name_trunc (current->subname,
358 tree_cols - 2 - 4 - 3 * j));
360 addch (' ');
362 /* Return to normal color */
363 attrset (TREE_NORMALC);
365 /* Calculate the next value for current */
366 if (tree_navigation_flag){
367 current = current->next;
368 while (current){
369 if (current->sublevel < tree->selected_ptr->sublevel){
370 if (strncmp (current->name, tree->selected_ptr->name,
371 strlen (current->name)) == 0)
372 break;
373 } else if (current->sublevel == tree->selected_ptr->sublevel){
374 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
375 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
376 break;
377 } else if (current->sublevel == tree->selected_ptr->sublevel+1
378 && strlen (tree->selected_ptr->name) > 1){
379 if (strncmp (current->name, tree->selected_ptr->name,
380 strlen (tree->selected_ptr->name)) == 0)
381 break;
383 current = current->next;
385 } else
386 current = current->next;
388 tree_show_mini_info (tree, tree_lines, tree_cols);
391 static void check_focus (WTree *tree)
393 if (tree->topdiff < 3)
394 tree->topdiff = 3;
395 else if (tree->topdiff >= tlines (tree) - 3)
396 tree->topdiff = tlines (tree) - 3 - 1;
399 void tree_move_backward (WTree *tree, int i)
401 tree_entry *current;
402 int j = 0;
404 if (tree_navigation_flag){
405 current = tree->selected_ptr;
406 while (j < i && current->prev
407 && current->prev->sublevel >= tree->selected_ptr->sublevel){
408 current = current->prev;
409 if (current->sublevel == tree->selected_ptr->sublevel){
410 tree->selected_ptr = current;
411 j ++;
414 i = j;
415 } else
416 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
417 tree->topdiff -= i;
418 check_focus (tree);
421 void tree_move_forward (WTree *tree, int i)
423 tree_entry *current;
424 int j = 0;
426 if (tree_navigation_flag){
427 current = tree->selected_ptr;
428 while (j < i && current->next
429 && current->next->sublevel >= tree->selected_ptr->sublevel){
430 current = current->next;
431 if (current->sublevel == tree->selected_ptr->sublevel){
432 tree->selected_ptr = current;
433 j ++;
436 i = j;
437 } else
438 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
439 tree->topdiff += i;
440 check_focus (tree);
443 void tree_move_to_child (WTree *tree)
445 tree_entry *current;
447 /* Do we have a starting point? */
448 if (!tree->selected_ptr)
449 return;
450 /* Take the next entry */
451 current = tree->selected_ptr->next;
452 /* Is it the child of the selected entry */
453 if (current && current->sublevel > tree->selected_ptr->sublevel){
454 /* Yes -> select this entry */
455 tree->selected_ptr = current;
456 tree->topdiff++;
457 check_focus (tree);
458 } else {
459 /* No -> rescan and try again */
460 tree_rescan_cmd (tree);
461 current = tree->selected_ptr->next;
462 if (current && current->sublevel > tree->selected_ptr->sublevel){
463 tree->selected_ptr = current;
464 tree->topdiff++;
465 check_focus (tree);
470 int tree_move_to_parent (WTree *tree)
472 tree_entry *current;
473 tree_entry *old;
475 if (!tree->selected_ptr)
476 return 0;
477 old = tree->selected_ptr;
478 current = tree->selected_ptr->prev;
479 while (current && current->sublevel >= tree->selected_ptr->sublevel){
480 current = current->prev;
481 tree->topdiff--;
483 if (!current)
484 current = tree->store->tree_first;
485 tree->selected_ptr = current;
486 check_focus (tree);
487 return tree->selected_ptr != old;
490 void tree_move_to_top (WTree *tree)
492 tree->selected_ptr = tree->store->tree_first;
493 tree->topdiff = 0;
496 void tree_move_to_bottom (WTree *tree)
498 tree->selected_ptr = tree->store->tree_last;
499 tree->topdiff = tlines (tree) - 3 - 1;
502 void tree_chdir (WTree *tree, char *dir)
504 tree_entry *current;
506 current = tree_store_whereis (dir);
507 if (current){
508 tree->selected_ptr = current;
509 check_focus (tree);
513 void
514 sync_tree (char *path)
516 tree_chdir (the_tree, path);
519 /* Handle mouse click */
520 void tree_event (WTree *tree, int y)
522 if (tree->tree_shown [y]){
523 tree->selected_ptr = tree->tree_shown [y];
524 tree->topdiff = y;
526 show_tree (tree);
529 static void chdir_sel (WTree *tree);
531 static void maybe_chdir (WTree *tree)
533 if (!(xtree_mode && tree->is_panel))
534 return;
535 if (is_idle ())
536 chdir_sel (tree);
539 /* Mouse callback */
540 static int event_callback (Gpm_Event *event, WTree *tree)
542 if (!(event->type & GPM_UP))
543 return MOU_ENDLOOP;
545 if (tree->is_panel)
546 event->y--;
548 event->y--;
550 if (!tree->active)
551 change_panel ();
553 if (event->y < 0){
554 tree_move_backward (tree, tlines (tree) - 1);
555 show_tree (tree);
557 else if (event->y >= tlines (tree)){
558 tree_move_forward (tree, tlines (tree) - 1);
559 show_tree (tree);
560 } else {
561 tree_event (tree, event->y);
562 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
563 chdir_sel (tree);
566 return MOU_ENDLOOP;
569 /* Search tree for text */
570 int search_tree (WTree *tree, char *text)
572 tree_entry *current;
573 int len;
574 int wrapped = 0;
575 int found = 0;
577 len = strlen (text);
578 current = tree->selected_ptr;
579 found = 0;
580 while (!wrapped || current != tree->selected_ptr){
581 if (strncmp (current->subname, text, len) == 0){
582 tree->selected_ptr = current;
583 found = 1;
584 break;
586 current = current->next;
587 if (!current){
588 current = tree->store->tree_first;
589 wrapped = 1;
591 tree->topdiff++;
593 check_focus (tree);
594 return found;
597 static void tree_do_search (WTree *tree, int key)
599 int l;
601 l = strlen (tree->search_buffer);
602 if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
603 tree->search_buffer [--l] = 0;
604 else {
605 if (key && l < sizeof (tree->search_buffer)){
606 tree->search_buffer [l] = key;
607 tree->search_buffer [l+1] = 0;
608 l++;
612 if (!search_tree (tree, tree->search_buffer))
613 tree->search_buffer [--l] = 0;
615 show_tree (tree);
616 maybe_chdir (tree);
619 void tree_rescan_cmd (WTree *tree)
621 char old_dir [MC_MAXPATHLEN];
623 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
624 mc_chdir (tree->selected_ptr->name))
625 return;
627 tree_store_rescan (tree->selected_ptr->name);
628 mc_chdir (old_dir);
631 int tree_forget_cmd (WTree *tree)
633 if (tree->selected_ptr)
634 tree_remove_entry (tree, tree->selected_ptr->name);
635 return 1;
638 void tree_copy (WTree *tree, char *default_dest)
640 char *dest;
641 long count = 0;
642 double bytes = 0;
643 FileOpContext *ctx;
645 if (!tree->selected_ptr)
646 return;
647 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
648 name_trunc (tree->selected_ptr->name, 50));
649 dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
650 if (!dest || !*dest){
651 return;
654 ctx = file_op_context_new ();
655 file_op_context_create_ui (ctx, OP_COPY, FALSE);
656 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
657 file_op_context_destroy (ctx);
659 g_free (dest);
662 static void tree_help_cmd (void)
664 char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
665 interactive_display (hlpfile, "[Directory Tree]");
666 g_free (hlpfile);
669 static int tree_copy_cmd (WTree *tree)
671 tree_copy (tree, "");
672 return 1;
675 void tree_move (WTree *tree, char *default_dest)
677 char *dest;
678 struct stat buf;
679 double bytes = 0;
680 long count = 0;
681 FileOpContext *ctx;
683 if (!tree->selected_ptr)
684 return;
685 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
686 name_trunc (tree->selected_ptr->name, 50));
687 dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
688 if (!dest || !*dest){
689 return;
691 if (stat (dest, &buf)){
692 message (1, _(" Error "), _(" Can't stat the destination \n %s "),
693 unix_error_string (errno));
694 g_free (dest);
695 return;
697 if (!S_ISDIR (buf.st_mode)){
698 message (1, _(" Error "), _(" The destination isn't a directory "));
699 g_free (dest);
700 return;
703 ctx = file_op_context_new ();
704 file_op_context_create_ui (ctx, OP_MOVE, FALSE);
705 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
706 file_op_context_destroy (ctx);
708 g_free (dest);
711 static int
712 tree_move_cmd (WTree *tree)
714 tree_move (tree, "");
715 return 1;
718 static int
719 tree_mkdir_cmd (WTree *tree)
721 char old_dir [MC_MAXPATHLEN];
723 if (!tree->selected_ptr)
724 return 0;
725 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
726 return 0;
727 if (chdir (tree->selected_ptr->name))
728 return 0;
729 /* FIXME
730 mkdir_cmd (tree);
732 tree_rescan_cmd (tree);
733 chdir (old_dir);
734 return 1;
737 static void
738 tree_rmdir_cmd (WTree *tree)
740 char old_dir [MC_MAXPATHLEN];
741 long count = 0;
742 double bytes = 0;
743 FileOpContext *ctx;
745 if (tree->selected_ptr){
746 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
747 return;
748 if (mc_chdir (PATH_SEP_STR))
749 return;
750 if (confirm_delete){
751 char *buf;
752 int result;
754 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
755 result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
756 g_free (buf);
757 if (result != 0){
758 return;
762 ctx = file_op_context_new ();
763 file_op_context_create_ui (ctx, OP_DELETE, FALSE);
764 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
765 tree_forget_cmd (tree);
766 file_op_context_destroy (ctx);
767 mc_chdir (old_dir);
768 return;
769 } else
770 return;
773 static void set_navig_label (Dlg_head *h);
775 static void
776 tree_toggle_navig (Dlg_head *h)
778 tree_navigation_flag = 1 - tree_navigation_flag;
779 set_navig_label (h);
782 void
783 set_navig_label (Dlg_head *h)
785 define_label_data (h, (Widget *)tree,
786 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
787 (void (*)(void *))tree_toggle_navig, h);
790 static void
791 move_down (WTree *tree)
793 tree_move_forward (tree, 1);
794 show_tree (tree);
795 maybe_chdir (tree);
798 static void
799 move_up (WTree *tree)
801 tree_move_backward (tree, 1);
802 show_tree (tree);
803 maybe_chdir (tree);
806 static void
807 move_home (WTree *tree)
809 tree_move_to_top (tree);
810 show_tree (tree);
811 maybe_chdir (tree);
814 static void
815 move_end (WTree *tree)
817 tree_move_to_bottom (tree);
818 show_tree (tree);
819 maybe_chdir (tree);
822 static int
823 move_left (WTree *tree)
825 int v;
827 if (tree_navigation_flag){
828 v = tree_move_to_parent (tree);
829 show_tree (tree);
830 maybe_chdir (tree);
831 return v;
833 return 0;
836 static int
837 move_right (WTree *tree)
839 if (tree_navigation_flag){
840 tree_move_to_child (tree);
841 show_tree (tree);
842 maybe_chdir (tree);
843 return 1;
845 return 0;
848 static void
849 move_prevp (WTree *tree)
851 tree_move_backward (tree, tlines (tree) - 1);
852 show_tree (tree);
853 maybe_chdir (tree);
856 static void
857 move_nextp (WTree *tree)
859 tree_move_forward (tree, tlines (tree) - 1);
860 show_tree (tree);
861 maybe_chdir (tree);
864 static void
865 chdir_sel (WTree *tree)
867 if (!tree->is_panel){
868 tree->done = 1;
869 return;
871 change_panel ();
872 if (do_cd (tree->selected_ptr->name, cd_exact)){
873 paint_panel (cpanel);
874 select_item (cpanel);
875 } else {
876 message (1, MSG_ERROR, _(" Can't chdir to \"%s\" \n %s "),
877 tree->selected_ptr->name, unix_error_string (errno));
879 change_panel ();
880 show_tree (tree);
881 return;
884 static void
885 start_search (WTree *tree)
887 int i;
889 if (tree->searching){
891 if (tree->selected_ptr == tree->store->tree_last)
892 tree_move_to_top(tree);
893 else {
894 /* set navigation mode temporarily to 'Static' because in
895 * dynamic navigation mode tree_move_forward will not move
896 * to a lower sublevel if necessary (sequent searches must
897 * start with the directory followed the last found directory)
899 i = tree_navigation_flag;
900 tree_navigation_flag = 0;
901 tree_move_forward (tree, 1);
902 tree_navigation_flag = i;
904 tree_do_search (tree, 0);
906 else {
907 tree->searching = 1;
908 tree->search_buffer[0] = 0;
912 static key_map tree_keymap [] = {
913 { XCTRL('n'), move_down },
914 { XCTRL('p'), move_up },
915 { KEY_DOWN, move_down },
916 { KEY_UP, move_up },
917 { '\n', chdir_sel },
918 { KEY_ENTER, chdir_sel },
919 { KEY_HOME, move_home },
920 { KEY_C1, move_end },
921 { KEY_END, move_end },
922 { KEY_A1, move_home },
923 { KEY_NPAGE, move_nextp },
924 { KEY_PPAGE, move_prevp },
925 { XCTRL('v'), move_nextp },
926 { ALT('v'), move_prevp },
927 { XCTRL('p'), move_up },
928 { XCTRL('p'), move_down },
929 { XCTRL('s'), start_search },
930 { ALT('s'), start_search },
931 { XCTRL('r'), tree_rescan_cmd },
932 { KEY_DC, tree_rmdir_cmd },
933 { 0, 0 }
936 static inline int
937 tree_key (WTree *tree, int key)
939 int i;
941 for (i = 0; tree_keymap [i].key_code; i++){
942 if (key == tree_keymap [i].key_code){
943 if (tree_keymap [i].fn != start_search)
944 tree->searching = 0;
945 (*tree_keymap [i].fn)(tree);
946 show_tree (tree);
947 return 1;
951 /* We do not want to use them if we do not need to */
952 /* Input line may want to take the motion key event */
953 if (key == KEY_LEFT)
954 return move_left (tree);
956 if (key == KEY_RIGHT)
957 return move_right (tree);
959 if (is_abort_char (key)) {
960 if (tree->is_panel) {
961 tree->searching = 0;
962 show_tree (tree);
963 return 1; /* eat abort char */
965 return 0; /* modal tree dialog: let upper layer see the
966 abort character and close the dialog */
969 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
970 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
971 if (tree->searching){
972 tree_do_search (tree, key);
973 show_tree (tree);
974 return 1;
977 if (!command_prompt) {
978 start_search (tree);
979 tree_do_search (tree, key);
980 return 1;
982 return tree->is_panel;
985 return 0;
988 static void
989 tree_frame (Dlg_head *h, WTree *tree)
991 attrset (NORMAL_COLOR);
992 widget_erase ((Widget*) tree);
993 if (tree->is_panel)
994 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
995 tree->widget.cols);
997 if (show_mini_info && tree->is_panel){
998 widget_move (tree, tlines (tree) + 1, 1);
999 hline (ACS_HLINE, tree->widget.cols - 2);
1004 static int
1005 tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
1007 switch (msg){
1008 case WIDGET_DRAW:
1009 tree_frame (h, tree);
1010 show_tree (tree);
1011 return 1;
1013 case WIDGET_KEY:
1014 return tree_key (tree, par);
1016 case WIDGET_FOCUS:
1017 tree->active = 1;
1018 define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
1019 define_label_data (h, (Widget *)tree,
1020 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
1021 define_label_data (h, (Widget *)tree,
1022 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
1023 define_label_data (h, (Widget *)tree,
1024 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
1025 define_label_data (h, (Widget *)tree,
1026 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1027 #if 0
1028 /* FIXME: mkdir is currently defunct */
1029 define_label_data (h, (Widget *)tree,
1030 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1031 #else
1032 define_label (h, (Widget *)tree, 7, "", 0);
1033 #endif
1034 define_label_data (h, (Widget *)tree,
1035 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
1036 set_navig_label (h);
1037 redraw_labels (h, (Widget *)tree);
1040 /* FIXME: Should find a better way of only displaying the
1041 currently selected item */
1042 show_tree (tree);
1043 return 1;
1045 /* FIXME: Should find a better way of changing the color of the
1046 selected item */
1047 case WIDGET_UNFOCUS:
1048 tree->active = 0;
1049 show_tree (tree);
1050 return 1;
1052 return default_proc (h, msg, par);
1055 WTree *
1056 tree_new (int is_panel, int y, int x, int lines, int cols)
1058 WTree *tree = g_new (WTree, 1);
1060 init_widget (&tree->widget, y, x, lines, cols, tcallback,
1061 (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
1062 tree->is_panel = is_panel;
1063 tree->selected_ptr = 0;
1065 tree->store = tree_store_init ();
1066 tree_store_add_entry_remove_hook (remove_callback, tree);
1067 tree->tree_shown = 0;
1068 tree->search_buffer [0] = 0;
1069 tree->topdiff = tree->widget.lines / 2;
1070 tree->searching = 0;
1071 tree->done = 0;
1072 tree->active = 0;
1074 /* We do not want to keep the cursor */
1075 widget_want_cursor (tree->widget, 0);
1076 load_tree (tree);
1077 return tree;