Forgot to remove some more .s strings and do a rename in order to prevent compiler...
[midnight-commander.git] / src / tree.c
blobf4e7ceeca099caa739b1cc55eae9514b0fab619d
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.
30 #include <config.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <string.h>
36 #include "global.h"
37 #include "tty.h"
38 #include "color.h"
39 #include "wtools.h" /* message() */
40 #include "dir.h"
41 #include "dialog.h"
42 #include "widget.h"
43 #include "panel.h"
44 #include "mouse.h"
45 #include "main.h"
46 #include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
47 #include "help.h"
48 #include "key.h" /* For mi_getch() */
49 #include "tree.h"
50 #include "treestore.h"
51 #include "cmd.h"
52 #include "history.h"
54 #define tlines(t) (t->is_panel ? t->widget.lines-2 - (show_mini_info ? 2 : 0) : t->widget.lines)
56 extern int command_prompt;
58 /* Use the color of the parent widget for the unselected entries */
59 #define TREE_NORMALC(h) (DLG_NORMALC (h))
61 /* Specifies the display mode: 1d or 2d */
62 static int tree_navigation_flag;
64 struct WTree {
65 Widget widget;
66 struct TreeStore *store;
67 tree_entry *selected_ptr; /* The selected directory */
68 char search_buffer[256]; /* Current search string */
69 tree_entry **tree_shown; /* Entries currently on screen */
70 int is_panel; /* panel or plain widget flag */
71 int active; /* if it's currently selected */
72 int searching; /* Are we on searching mode? */
73 int topdiff; /* The difference between the topmost
74 shown and the selected */
77 /* Forwards */
78 static void save_tree (WTree *tree);
79 static void tree_rescan_cmd (WTree *);
81 static tree_entry *back_ptr (tree_entry *ptr, int *count)
83 int i = 0;
85 while (ptr && ptr->prev && i < *count){
86 ptr = ptr->prev;
87 i ++;
89 *count = i;
90 return ptr;
93 static tree_entry *forw_ptr (tree_entry *ptr, int *count)
95 int i = 0;
97 while (ptr && ptr->next && i < *count){
98 ptr = ptr->next;
99 i ++;
101 *count = i;
102 return ptr;
105 static void
106 remove_callback (tree_entry *entry, void *data)
108 WTree *tree = data;
110 if (tree->selected_ptr == entry){
111 if (tree->selected_ptr->next)
112 tree->selected_ptr = tree->selected_ptr->next;
113 else
114 tree->selected_ptr = tree->selected_ptr->prev;
118 static void tree_remove_entry (WTree *tree, char *name)
120 (void) tree;
121 tree_store_remove_entry (name);
124 static void tree_destroy (WTree *tree)
126 tree_store_remove_entry_remove_hook (remove_callback);
127 save_tree (tree);
129 g_free (tree->tree_shown);
130 tree->tree_shown = 0;
131 tree->selected_ptr = NULL;
134 /* Loads the .mc.tree file */
135 static void load_tree (WTree *tree)
137 tree_store_load ();
139 tree->selected_ptr = tree->store->tree_first;
140 tree_chdir (tree, home_dir);
143 /* Save the .mc.tree file */
144 static void save_tree (WTree *tree)
146 int error;
148 (void) tree;
149 error = tree_store_save ();
151 if (error){
152 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
153 unix_error_string (error));
157 static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
159 Dlg_head *h = tree->widget.parent;
160 int line;
162 /* Show mini info */
163 if (tree->is_panel){
164 if (!show_mini_info)
165 return;
166 line = tree_lines+2;
167 } else
168 line = tree_lines+1;
170 widget_move (&tree->widget, line, 1);
171 hline (' ', tree_cols);
172 widget_move (&tree->widget, line, 1);
174 if (tree->searching){
175 /* Show search string */
176 attrset (TREE_NORMALC (h));
177 attrset (DLG_FOCUSC (h));
178 addch (PATH_SEP);
180 addstr ((char *) name_trunc (tree->search_buffer, tree_cols-2));
181 addch (' ');
182 attrset (DLG_FOCUSC (h));
183 } else {
184 /* Show full name of selected directory */
185 addstr ((char *) name_trunc (tree->selected_ptr->name, tree_cols));
189 static void show_tree (WTree *tree)
191 Dlg_head *h = tree->widget.parent;
192 tree_entry *current;
193 int i, j, topsublevel;
194 int x, y;
195 int tree_lines, tree_cols;
197 /* Initialize */
198 x = y = 0;
199 tree_lines = tlines (tree);
200 tree_cols = tree->widget.cols;
202 attrset (TREE_NORMALC (h));
203 widget_move ((Widget*)tree, y, x);
204 if (tree->is_panel){
205 tree_cols -= 2;
206 x = y = 1;
209 g_free (tree->tree_shown);
210 tree->tree_shown = g_new (tree_entry*, tree_lines);
212 for (i = 0; i < tree_lines; i++)
213 tree->tree_shown [i] = NULL;
214 if (tree->store->tree_first)
215 topsublevel = tree->store->tree_first->sublevel;
216 else
217 topsublevel = 0;
218 if (!tree->selected_ptr){
219 tree->selected_ptr = tree->store->tree_first;
220 tree->topdiff = 0;
222 current = tree->selected_ptr;
224 /* Calculate the directory which is to be shown on the topmost line */
225 if (tree_navigation_flag){
226 i = 0;
227 while (current->prev && i < tree->topdiff){
228 current = current->prev;
229 if (current->sublevel < tree->selected_ptr->sublevel){
230 if (strncmp (current->name, tree->selected_ptr->name,
231 strlen (current->name)) == 0)
232 i++;
233 } else if (current->sublevel == tree->selected_ptr->sublevel){
234 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
235 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
236 i++;
237 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
238 && strlen (tree->selected_ptr->name) > 1){
239 if (strncmp (current->name, tree->selected_ptr->name,
240 strlen (tree->selected_ptr->name)) == 0)
241 i++;
244 tree->topdiff = i;
245 } else
246 current = back_ptr (current, &tree->topdiff);
248 /* Loop for every line */
249 for (i = 0; i < tree_lines; i++){
250 /* Move to the beginning of the line */
251 widget_move (&tree->widget, y+i, x);
253 hline (' ', tree_cols);
254 widget_move (&tree->widget, y+i, x);
256 if (!current)
257 continue;
259 tree->tree_shown [i] = current;
260 if (current->sublevel == topsublevel){
262 /* Top level directory */
263 if (tree->active && current == tree->selected_ptr) {
264 if (!use_colors && !tree->is_panel)
265 attrset (MARKED_COLOR);
266 else
267 attrset (SELECTED_COLOR);
270 /* Show full name */
271 addstr ((char *) name_trunc (current->name, tree_cols - 6));
272 } else{
273 /* Sub level directory */
275 acs ();
276 /* Output branch parts */
277 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
278 if (tree_cols - 8 - 3 * j < 9)
279 break;
280 addch (' ');
281 if (current->submask & (1 << (j + topsublevel + 1)))
282 addch (ACS_VLINE);
283 else
284 addch (' ');
285 addch (' ');
287 addch (' '); j++;
288 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
289 addch (ACS_LLCORNER);
290 else
291 addch (ACS_LTEE);
292 addch (ACS_HLINE);
293 noacs ();
295 if (tree->active && current == tree->selected_ptr) {
296 /* Selected directory -> change color */
297 if (!use_colors && !tree->is_panel)
298 attrset (MARKED_COLOR);
299 else
300 attrset (SELECTED_COLOR);
303 /* Show sub-name */
304 addch (' ');
305 addstr ((char *) name_trunc (current->subname,
306 tree_cols - 2 - 4 - 3 * j));
308 addch (' ');
310 /* Return to normal color */
311 attrset (TREE_NORMALC (h));
313 /* Calculate the next value for current */
314 current = current->next;
315 if (tree_navigation_flag){
316 while (current){
317 if (current->sublevel < tree->selected_ptr->sublevel){
318 if (strncmp (current->name, tree->selected_ptr->name,
319 strlen (current->name)) == 0)
320 break;
321 } else if (current->sublevel == tree->selected_ptr->sublevel){
322 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
323 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
324 break;
325 } else if (current->sublevel == tree->selected_ptr->sublevel+1
326 && strlen (tree->selected_ptr->name) > 1){
327 if (strncmp (current->name, tree->selected_ptr->name,
328 strlen (tree->selected_ptr->name)) == 0)
329 break;
331 current = current->next;
335 tree_show_mini_info (tree, tree_lines, tree_cols);
338 static void check_focus (WTree *tree)
340 if (tree->topdiff < 3)
341 tree->topdiff = 3;
342 else if (tree->topdiff >= tlines (tree) - 3)
343 tree->topdiff = tlines (tree) - 3 - 1;
346 static void tree_move_backward (WTree *tree, int i)
348 tree_entry *current;
349 int j = 0;
351 if (tree_navigation_flag){
352 current = tree->selected_ptr;
353 while (j < i && current->prev
354 && current->prev->sublevel >= tree->selected_ptr->sublevel){
355 current = current->prev;
356 if (current->sublevel == tree->selected_ptr->sublevel){
357 tree->selected_ptr = current;
358 j ++;
361 i = j;
362 } else
363 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
364 tree->topdiff -= i;
365 check_focus (tree);
368 static void tree_move_forward (WTree *tree, int i)
370 tree_entry *current;
371 int j = 0;
373 if (tree_navigation_flag){
374 current = tree->selected_ptr;
375 while (j < i && current->next
376 && current->next->sublevel >= tree->selected_ptr->sublevel){
377 current = current->next;
378 if (current->sublevel == tree->selected_ptr->sublevel){
379 tree->selected_ptr = current;
380 j ++;
383 i = j;
384 } else
385 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
386 tree->topdiff += i;
387 check_focus (tree);
390 static void tree_move_to_child (WTree *tree)
392 tree_entry *current;
394 /* Do we have a starting point? */
395 if (!tree->selected_ptr)
396 return;
397 /* Take the next entry */
398 current = tree->selected_ptr->next;
399 /* Is it the child of the selected entry */
400 if (current && current->sublevel > tree->selected_ptr->sublevel){
401 /* Yes -> select this entry */
402 tree->selected_ptr = current;
403 tree->topdiff++;
404 check_focus (tree);
405 } else {
406 /* No -> rescan and try again */
407 tree_rescan_cmd (tree);
408 current = tree->selected_ptr->next;
409 if (current && current->sublevel > tree->selected_ptr->sublevel){
410 tree->selected_ptr = current;
411 tree->topdiff++;
412 check_focus (tree);
417 static int tree_move_to_parent (WTree *tree)
419 tree_entry *current;
420 tree_entry *old;
422 if (!tree->selected_ptr)
423 return 0;
424 old = tree->selected_ptr;
425 current = tree->selected_ptr->prev;
426 while (current && current->sublevel >= tree->selected_ptr->sublevel){
427 current = current->prev;
428 tree->topdiff--;
430 if (!current)
431 current = tree->store->tree_first;
432 tree->selected_ptr = current;
433 check_focus (tree);
434 return tree->selected_ptr != old;
437 static void tree_move_to_top (WTree *tree)
439 tree->selected_ptr = tree->store->tree_first;
440 tree->topdiff = 0;
443 static void tree_move_to_bottom (WTree *tree)
445 tree->selected_ptr = tree->store->tree_last;
446 tree->topdiff = tlines (tree) - 3 - 1;
449 void tree_chdir (WTree *tree, const char *dir)
451 tree_entry *current;
453 current = tree_store_whereis (dir);
454 if (current){
455 tree->selected_ptr = current;
456 check_focus (tree);
460 void
461 sync_tree (const char *path)
463 tree_chdir (the_tree, path);
466 /* Handle mouse click */
467 static void
468 tree_event (WTree *tree, int y)
470 if (tree->tree_shown [y]){
471 tree->selected_ptr = tree->tree_shown [y];
472 tree->topdiff = y;
474 show_tree (tree);
477 static void chdir_sel (WTree *tree);
479 static void maybe_chdir (WTree *tree)
481 if (!(xtree_mode && tree->is_panel))
482 return;
483 if (is_idle ())
484 chdir_sel (tree);
487 /* Mouse callback */
488 static int
489 event_callback (Gpm_Event *event, void *data)
491 WTree *tree = data;
493 if (!(event->type & GPM_UP))
494 return MOU_NORMAL;
496 if (tree->is_panel)
497 event->y--;
499 event->y--;
501 if (!tree->active)
502 change_panel ();
504 if (event->y < 0){
505 tree_move_backward (tree, tlines (tree) - 1);
506 show_tree (tree);
508 else if (event->y >= tlines (tree)){
509 tree_move_forward (tree, tlines (tree) - 1);
510 show_tree (tree);
511 } else {
512 tree_event (tree, event->y);
513 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
514 chdir_sel (tree);
517 return MOU_NORMAL;
520 /* Search tree for text */
521 static int search_tree (WTree *tree, char *text)
523 tree_entry *current;
524 int len;
525 int wrapped = 0;
526 int found = 0;
528 len = strlen (text);
529 current = tree->selected_ptr;
530 found = 0;
531 while (!wrapped || current != tree->selected_ptr){
532 if (strncmp (current->subname, text, len) == 0){
533 tree->selected_ptr = current;
534 found = 1;
535 break;
537 current = current->next;
538 if (!current){
539 current = tree->store->tree_first;
540 wrapped = 1;
542 tree->topdiff++;
544 check_focus (tree);
545 return found;
548 static void tree_do_search (WTree *tree, int key)
550 size_t l;
552 l = strlen (tree->search_buffer);
553 if (l && (key == KEY_BACKSPACE))
554 tree->search_buffer [--l] = 0;
555 else {
556 if (key && l < sizeof (tree->search_buffer)){
557 tree->search_buffer [l] = key;
558 tree->search_buffer [l+1] = 0;
559 l++;
563 if (!search_tree (tree, tree->search_buffer))
564 tree->search_buffer [--l] = 0;
566 show_tree (tree);
567 maybe_chdir (tree);
570 static void
571 tree_rescan_cmd (WTree *tree)
573 char old_dir [MC_MAXPATHLEN];
575 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
576 mc_chdir (tree->selected_ptr->name))
577 return;
579 tree_store_rescan (tree->selected_ptr->name);
580 mc_chdir (old_dir);
583 static void
584 tree_forget_cmd (void *data)
586 WTree *tree = data;
587 if (tree->selected_ptr)
588 tree_remove_entry (tree, tree->selected_ptr->name);
591 static void tree_copy (WTree *tree, const char *default_dest)
593 char *dest;
594 off_t count = 0;
595 double bytes = 0;
596 FileOpContext *ctx;
598 if (!tree->selected_ptr)
599 return;
600 g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
601 name_trunc (tree->selected_ptr->name, 50));
602 dest = input_expand_dialog (_(" Copy "), cmd_buf, MC_HISTORY_FM_TREE_COPY, default_dest);
604 if (!dest)
605 return;
607 if (!*dest){
608 g_free (dest);
609 return;
612 ctx = file_op_context_new (OP_COPY);
613 file_op_context_create_ui (ctx, FALSE);
614 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
615 file_op_context_destroy (ctx);
617 g_free (dest);
620 static void
621 tree_help_cmd (void)
623 interactive_display (NULL, "[Directory Tree]");
626 static void
627 tree_copy_cmd (void *data)
629 WTree *tree = data;
630 tree_copy (tree, "");
633 static void tree_move (WTree *tree, const char *default_dest)
635 char *dest;
636 struct stat buf;
637 double bytes = 0;
638 off_t count = 0;
639 FileOpContext *ctx;
641 if (!tree->selected_ptr)
642 return;
643 g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
644 name_trunc (tree->selected_ptr->name, 50));
645 dest = input_expand_dialog (_(" Move "), cmd_buf, MC_HISTORY_FM_TREE_MOVE, default_dest);
646 if (!dest)
647 return;
648 if (!*dest){
649 g_free (dest);
650 return;
652 if (stat (dest, &buf)){
653 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
654 unix_error_string (errno));
655 g_free (dest);
656 return;
658 if (!S_ISDIR (buf.st_mode)){
659 file_error (_(" Destination \"%s\" must be a directory \n %s "),
660 dest);
661 g_free (dest);
662 return;
665 ctx = file_op_context_new (OP_MOVE);
666 file_op_context_create_ui (ctx, FALSE);
667 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
668 file_op_context_destroy (ctx);
670 g_free (dest);
673 static void
674 tree_move_cmd (void *data)
676 WTree *tree = data;
677 tree_move (tree, "");
680 #if 0
681 static void
682 tree_mkdir_cmd (WTree *tree)
684 char old_dir [MC_MAXPATHLEN];
686 if (!tree->selected_ptr)
687 return;
688 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
689 return;
690 if (chdir (tree->selected_ptr->name))
691 return;
692 /* FIXME
693 mkdir_cmd (tree);
695 tree_rescan_cmd (tree);
696 chdir (old_dir);
698 #endif
700 static void
701 tree_rmdir_cmd (WTree *tree)
703 off_t count = 0;
704 double bytes = 0;
705 FileOpContext *ctx;
707 if (!tree->selected_ptr)
708 return;
710 if (confirm_delete) {
711 char *buf;
712 int result;
714 buf =
715 g_strdup_printf (_(" Delete %s? "),
716 tree->selected_ptr->name);
717 result =
718 query_dialog (_(" Delete "), buf, D_ERROR, 2, _("&Yes"), _("&No"));
719 g_free (buf);
720 if (result != 0)
721 return;
724 ctx = file_op_context_new (OP_DELETE);
725 file_op_context_create_ui (ctx, FALSE);
726 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) ==
727 FILE_CONT)
728 tree_forget_cmd (tree);
729 file_op_context_destroy (ctx);
732 static void set_navig_label (WTree *tree);
734 static void
735 tree_toggle_navig (void *data)
737 WTree *tree = data;
738 /* FIXME: invalid use of boolean variable */
739 tree_navigation_flag = 1 - tree_navigation_flag;
740 set_navig_label (tree);
743 static void
744 set_navig_label (WTree *tree)
746 buttonbar_set_label_data (tree->widget.parent, 4,
747 tree_navigation_flag ? _("Static") : _("Dynamc"),
748 tree_toggle_navig, tree);
751 static void
752 move_down (WTree *tree)
754 tree_move_forward (tree, 1);
755 show_tree (tree);
756 maybe_chdir (tree);
759 static void
760 move_up (WTree *tree)
762 tree_move_backward (tree, 1);
763 show_tree (tree);
764 maybe_chdir (tree);
767 static void
768 move_home (WTree *tree)
770 tree_move_to_top (tree);
771 show_tree (tree);
772 maybe_chdir (tree);
775 static void
776 move_end (WTree *tree)
778 tree_move_to_bottom (tree);
779 show_tree (tree);
780 maybe_chdir (tree);
783 static int
784 move_left (WTree *tree)
786 int v;
788 if (tree_navigation_flag){
789 v = tree_move_to_parent (tree);
790 show_tree (tree);
791 maybe_chdir (tree);
792 return v;
794 return 0;
797 static int
798 move_right (WTree *tree)
800 if (tree_navigation_flag){
801 tree_move_to_child (tree);
802 show_tree (tree);
803 maybe_chdir (tree);
804 return 1;
806 return 0;
809 static void
810 move_prevp (WTree *tree)
812 tree_move_backward (tree, tlines (tree) - 1);
813 show_tree (tree);
814 maybe_chdir (tree);
817 static void
818 move_nextp (WTree *tree)
820 tree_move_forward (tree, tlines (tree) - 1);
821 show_tree (tree);
822 maybe_chdir (tree);
825 static void
826 chdir_sel (WTree *tree)
828 if (!tree->is_panel) {
829 return;
831 change_panel ();
832 if (do_cd (tree->selected_ptr->name, cd_exact)) {
833 select_item (current_panel);
834 } else {
835 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
836 tree->selected_ptr->name, unix_error_string (errno));
838 change_panel ();
839 show_tree (tree);
840 return;
843 static void
844 tree_start_search (WTree *tree)
846 int i;
848 if (tree->searching){
850 if (tree->selected_ptr == tree->store->tree_last)
851 tree_move_to_top(tree);
852 else {
853 /* set navigation mode temporarily to 'Static' because in
854 * dynamic navigation mode tree_move_forward will not move
855 * to a lower sublevel if necessary (sequent searches must
856 * start with the directory followed the last found directory)
858 i = tree_navigation_flag;
859 tree_navigation_flag = 0;
860 tree_move_forward (tree, 1);
861 tree_navigation_flag = i;
863 tree_do_search (tree, 0);
865 else {
866 tree->searching = 1;
867 tree->search_buffer[0] = 0;
871 typedef void (*tree_key_action) (WTree *);
872 typedef struct {
873 int key_code;
874 tree_key_action fn;
875 } tree_key_map;
877 static const tree_key_map tree_keymap [] = {
878 { XCTRL('n'), move_down },
879 { XCTRL('p'), move_up },
880 { KEY_DOWN, move_down },
881 { KEY_UP, move_up },
882 { '\n', chdir_sel },
883 { KEY_ENTER, chdir_sel },
884 { KEY_HOME, move_home },
885 { KEY_A1, move_home },
886 { ALT ('<'), move_home },
887 { KEY_END, move_end },
888 { KEY_C1, move_end },
889 { ALT ('>'), move_end },
890 { KEY_NPAGE, move_nextp },
891 { KEY_PPAGE, move_prevp },
892 { XCTRL('v'), move_nextp },
893 { ALT('v'), move_prevp },
894 { XCTRL('p'), move_up },
895 { XCTRL('p'), move_down },
896 { XCTRL('s'), tree_start_search },
897 { ALT('s'), tree_start_search },
898 { XCTRL('r'), tree_rescan_cmd },
899 { KEY_DC, tree_rmdir_cmd },
900 { 0, 0 }
903 static inline cb_ret_t
904 tree_key (WTree *tree, int key)
906 int i;
908 for (i = 0; tree_keymap [i].key_code; i++){
909 if (key == tree_keymap [i].key_code){
910 if (tree_keymap [i].fn != tree_start_search)
911 tree->searching = 0;
912 (*tree_keymap [i].fn)(tree);
913 show_tree (tree);
914 return MSG_HANDLED;
918 /* We do not want to use them if we do not need to */
919 /* Input line may want to take the motion key event */
920 if (key == KEY_LEFT)
921 return move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
923 if (key == KEY_RIGHT)
924 return move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
926 if (is_abort_char (key)) {
927 if (tree->is_panel) {
928 tree->searching = 0;
929 show_tree (tree);
930 return MSG_HANDLED; /* eat abort char */
932 /* modal tree dialog: let upper layer see the
933 abort character and close the dialog */
934 return MSG_NOT_HANDLED;
937 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
938 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
939 if (tree->searching){
940 tree_do_search (tree, key);
941 show_tree (tree);
942 return MSG_HANDLED;
945 if (!command_prompt) {
946 tree_start_search (tree);
947 tree_do_search (tree, key);
948 return MSG_HANDLED;
950 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
953 return MSG_NOT_HANDLED;
956 static void
957 tree_frame (Dlg_head *h, WTree *tree)
959 attrset (NORMAL_COLOR);
960 widget_erase ((Widget*) tree);
961 if (tree->is_panel)
962 draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
963 tree->widget.cols);
965 if (show_mini_info && tree->is_panel){
966 widget_move (tree, tlines (tree) + 1, 1);
967 hline (ACS_HLINE, tree->widget.cols - 2);
971 static void
972 tree_rescan_command (void *data)
974 WTree *tree = data;
975 tree_rescan_cmd (tree);
978 static void
979 tree_rmdir_command (void *data)
981 WTree *tree = data;
982 tree_rmdir_cmd (tree);
985 static cb_ret_t
986 tree_callback (Widget *w, widget_msg_t msg, int parm)
988 WTree *tree = (WTree *) w;
989 Dlg_head *h = tree->widget.parent;
991 switch (msg) {
992 case WIDGET_DRAW:
993 tree_frame (h, tree);
994 show_tree (tree);
995 return MSG_HANDLED;
997 case WIDGET_KEY:
998 return tree_key (tree, parm);
1000 case WIDGET_FOCUS:
1001 tree->active = 1;
1002 buttonbar_set_label (h, 1, _("Help"), tree_help_cmd);
1003 buttonbar_set_label_data (h, 2, _("Rescan"),
1004 tree_rescan_command, tree);
1005 buttonbar_set_label_data (h, 3, _("Forget"), tree_forget_cmd, tree);
1006 buttonbar_set_label_data (h, 5, _("Copy"), tree_copy_cmd, tree);
1007 buttonbar_set_label_data (h, 6, _("RenMov"), tree_move_cmd, tree);
1008 #if 0
1009 /* FIXME: mkdir is currently defunct */
1010 buttonbar_set_label_data (h, 7, _("Mkdir"), tree_mkdir_cmd, tree);
1011 #else
1012 buttonbar_clear_label (h, 7);
1013 #endif
1014 buttonbar_set_label_data (h, 8, _("Rmdir"), tree_rmdir_command, tree);
1015 set_navig_label (tree);
1016 buttonbar_redraw (h);
1019 /* FIXME: Should find a better way of only displaying the
1020 currently selected item */
1021 show_tree (tree);
1022 return MSG_HANDLED;
1024 /* FIXME: Should find a better way of changing the color of the
1025 selected item */
1027 case WIDGET_UNFOCUS:
1028 tree->active = 0;
1029 show_tree (tree);
1030 return MSG_HANDLED;
1032 case WIDGET_DESTROY:
1033 tree_destroy (tree);
1034 return MSG_HANDLED;
1036 default:
1037 return default_proc (msg, parm);
1041 WTree *
1042 tree_new (int is_panel, int y, int x, int lines, int cols)
1044 WTree *tree = g_new (WTree, 1);
1046 init_widget (&tree->widget, y, x, lines, cols,
1047 tree_callback, event_callback);
1048 tree->is_panel = is_panel;
1049 tree->selected_ptr = 0;
1051 tree->store = tree_store_get ();
1052 tree_store_add_entry_remove_hook (remove_callback, tree);
1053 tree->tree_shown = 0;
1054 tree->search_buffer[0] = 0;
1055 tree->topdiff = tree->widget.lines / 2;
1056 tree->searching = 0;
1057 tree->active = 0;
1059 /* We do not want to keep the cursor */
1060 widget_want_cursor (tree->widget, 0);
1061 load_tree (tree);
1062 return tree;
1065 /* Return name of the currently selected entry */
1066 char *
1067 tree_selected_name (WTree *tree)
1069 return tree->selected_ptr->name;