Merge branch '1396_with_search_engine'
[midnight-commander.git] / src / tree.c
blob80881c46a09dd1c8757a524eedaa30111394b585
1 /* Directory tree browser for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
5 Written: 1994, 1996 Janne Kukonlehto
6 1997 Norbert Warmuth
7 1996, 1999 Miguel de Icaza
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 This module has been converted to be a widget.
25 The program load and saves the tree each time the tree widget is
26 created and destroyed. This is required for the future vfs layer,
27 it will be possible to have tree views over virtual file systems.
31 /** \file tree.c
32 * \brief Source: directory tree browser
35 #include <config.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <sys/types.h>
42 #include "global.h"
44 #include "../src/tty/tty.h"
45 #include "../src/skin/skin.h"
46 #include "../src/tty/mouse.h"
47 #include "../src/tty/key.h"
49 #include "wtools.h" /* message() */
50 #include "dir.h"
51 #include "dialog.h"
52 #include "widget.h"
53 #include "panel.h"
54 #include "main.h"
55 #include "main-widgets.h" /* the_menubar */
56 #include "menu.h" /* menubar_visible */
57 #include "file.h" /* copy_dir_dir(), move_dir_dir(), erase_dir() */
58 #include "layout.h" /* command_prompt */
59 #include "help.h"
60 #include "treestore.h"
61 #include "cmd.h"
62 #include "cmddef.h"
63 #include "keybind.h"
64 #include "history.h"
65 #include "strutil.h"
66 #include "fileloc.h"
67 #include "tree.h"
69 const global_keymap_t *tree_map;
71 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (show_mini_info ? 2 : 0) : t->widget.lines)
73 /* Use the color of the parent widget for the unselected entries */
74 #define TREE_NORMALC(h) (DLG_NORMALC (h))
76 /* Specifies the display mode: 1d or 2d */
77 static gboolean tree_navigation_flag = FALSE;
79 struct WTree {
80 Widget widget;
81 struct TreeStore *store;
82 tree_entry *selected_ptr; /* The selected directory */
83 char search_buffer[256]; /* Current search string */
84 tree_entry **tree_shown; /* Entries currently on screen */
85 int is_panel; /* panel or plain widget flag */
86 int active; /* if it's currently selected */
87 int searching; /* Are we on searching mode? */
88 int topdiff; /* The difference between the topmost
89 shown and the selected */
92 /* Forwards */
93 static void tree_rescan (void *data);
95 static tree_entry *
96 back_ptr (tree_entry *ptr, int *count)
98 int i = 0;
100 while (ptr && ptr->prev && i < *count){
101 ptr = ptr->prev;
102 i ++;
104 *count = i;
105 return ptr;
108 static tree_entry *
109 forw_ptr (tree_entry *ptr, int *count)
111 int i = 0;
113 while (ptr && ptr->next && i < *count){
114 ptr = ptr->next;
115 i ++;
117 *count = i;
118 return ptr;
121 static void
122 remove_callback (tree_entry *entry, void *data)
124 WTree *tree = data;
126 if (tree->selected_ptr == entry){
127 if (tree->selected_ptr->next)
128 tree->selected_ptr = tree->selected_ptr->next;
129 else
130 tree->selected_ptr = tree->selected_ptr->prev;
134 /* Save the ~/.mc/Tree file */
135 static void
136 save_tree (WTree *tree)
138 int error;
139 char *tree_name;
141 (void) tree;
142 error = tree_store_save ();
145 if (error){
146 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR,
147 MC_TREESTORE_FILE, (char *) NULL);
148 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
149 unix_error_string (error));
150 g_free (tree_name);
154 static void
155 tree_remove_entry (WTree *tree, char *name)
157 (void) tree;
158 tree_store_remove_entry (name);
161 static void
162 tree_destroy (WTree *tree)
164 tree_store_remove_entry_remove_hook (remove_callback);
165 save_tree (tree);
167 g_free (tree->tree_shown);
168 tree->tree_shown = 0;
169 tree->selected_ptr = NULL;
172 /* Loads the .mc.tree file */
173 static void
174 load_tree (WTree *tree)
176 tree_store_load ();
178 tree->selected_ptr = tree->store->tree_first;
179 tree_chdir (tree, home_dir);
182 static void
183 tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
185 Dlg_head *h = tree->widget.parent;
186 int line;
188 /* Show mini info */
189 if (tree->is_panel){
190 if (!show_mini_info)
191 return;
192 line = tree_lines+2;
193 } else
194 line = tree_lines+1;
196 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
197 widget_move (&tree->widget, line, 1);
199 if (tree->searching){
200 /* Show search string */
201 tty_setcolor (TREE_NORMALC (h));
202 tty_setcolor (DLG_FOCUSC (h));
203 tty_print_char (PATH_SEP);
205 tty_print_string (str_fit_to_term (tree->search_buffer,
206 tree_cols - 2, J_LEFT_FIT));
207 tty_print_char (' ');
208 tty_setcolor (DLG_FOCUSC (h));
209 } else {
210 /* Show full name of selected directory */
211 tty_print_string (str_fit_to_term (tree->selected_ptr->name,
212 tree_cols, J_LEFT_FIT));
216 static void
217 show_tree (WTree *tree)
219 Dlg_head *h = tree->widget.parent;
220 tree_entry *current;
221 int i, j, topsublevel;
222 int x, y;
223 int tree_lines, tree_cols;
225 /* Initialize */
226 x = y = 0;
227 tree_lines = tlines (tree);
228 tree_cols = tree->widget.cols;
230 tty_setcolor (TREE_NORMALC (h));
231 widget_move ((Widget*)tree, y, x);
232 if (tree->is_panel){
233 tree_cols -= 2;
234 x = y = 1;
237 g_free (tree->tree_shown);
238 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
240 if (tree->store->tree_first)
241 topsublevel = tree->store->tree_first->sublevel;
242 else
243 topsublevel = 0;
244 if (!tree->selected_ptr){
245 tree->selected_ptr = tree->store->tree_first;
246 tree->topdiff = 0;
248 current = tree->selected_ptr;
250 /* Calculate the directory which is to be shown on the topmost line */
251 if (!tree_navigation_flag)
252 current = back_ptr (current, &tree->topdiff);
253 else {
254 i = 0;
255 while (current->prev && i < tree->topdiff){
256 current = current->prev;
257 if (current->sublevel < tree->selected_ptr->sublevel){
258 if (strncmp (current->name, tree->selected_ptr->name,
259 strlen (current->name)) == 0)
260 i++;
261 } else if (current->sublevel == tree->selected_ptr->sublevel){
262 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
263 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
264 i++;
265 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
266 && strlen (tree->selected_ptr->name) > 1){
267 if (strncmp (current->name, tree->selected_ptr->name,
268 strlen (tree->selected_ptr->name)) == 0)
269 i++;
272 tree->topdiff = i;
275 /* Loop for every line */
276 for (i = 0; i < tree_lines; i++){
277 /* Move to the beginning of the line */
278 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x, ' ', tree_cols);
280 if (!current)
281 continue;
283 tree->tree_shown [i] = current;
284 if (current->sublevel == topsublevel){
286 /* Top level directory */
287 if (tree->active && current == tree->selected_ptr) {
288 if (!tty_use_colors () && !tree->is_panel)
289 tty_setcolor (MARKED_COLOR);
290 else
291 tty_setcolor (SELECTED_COLOR);
294 /* Show full name */
295 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
296 } else{
297 /* Sub level directory */
299 tty_set_alt_charset (TRUE);
300 /* Output branch parts */
301 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
302 if (tree_cols - 8 - 3 * j < 9)
303 break;
304 tty_print_char (' ');
305 if (current->submask & (1 << (j + topsublevel + 1)))
306 tty_print_char (ACS_VLINE);
307 else
308 tty_print_char (' ');
309 tty_print_char (' ');
311 tty_print_char (' '); j++;
312 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
313 tty_print_char (ACS_LLCORNER);
314 else
315 tty_print_char (ACS_LTEE);
316 tty_print_char (ACS_HLINE);
317 tty_set_alt_charset (FALSE);
319 if (tree->active && current == tree->selected_ptr) {
320 /* Selected directory -> change color */
321 if (!tty_use_colors () && !tree->is_panel)
322 tty_setcolor (MARKED_COLOR);
323 else
324 tty_setcolor (SELECTED_COLOR);
327 /* Show sub-name */
328 tty_print_char (' ');
329 tty_print_string (str_fit_to_term (current->subname,
330 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
332 tty_print_char (' ');
334 /* Return to normal color */
335 tty_setcolor (TREE_NORMALC (h));
337 /* Calculate the next value for current */
338 current = current->next;
339 if (tree_navigation_flag){
340 while (current){
341 if (current->sublevel < tree->selected_ptr->sublevel){
342 if (strncmp (current->name, tree->selected_ptr->name,
343 strlen (current->name)) == 0)
344 break;
345 } else if (current->sublevel == tree->selected_ptr->sublevel){
346 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
347 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
348 break;
349 } else if (current->sublevel == tree->selected_ptr->sublevel+1
350 && strlen (tree->selected_ptr->name) > 1){
351 if (strncmp (current->name, tree->selected_ptr->name,
352 strlen (tree->selected_ptr->name)) == 0)
353 break;
355 current = current->next;
359 tree_show_mini_info (tree, tree_lines, tree_cols);
362 static void
363 tree_check_focus (WTree *tree)
365 if (tree->topdiff < 3)
366 tree->topdiff = 3;
367 else if (tree->topdiff >= tlines (tree) - 3)
368 tree->topdiff = tlines (tree) - 3 - 1;
371 static void
372 tree_move_backward (WTree *tree, int i)
374 if (!tree_navigation_flag)
375 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
376 else {
377 tree_entry *current;
378 int j = 0;
380 current = tree->selected_ptr;
381 while (j < i && current->prev
382 && current->prev->sublevel >= tree->selected_ptr->sublevel){
383 current = current->prev;
384 if (current->sublevel == tree->selected_ptr->sublevel){
385 tree->selected_ptr = current;
386 j++;
389 i = j;
392 tree->topdiff -= i;
393 tree_check_focus (tree);
396 static void
397 tree_move_forward (WTree *tree, int i)
399 if (!tree_navigation_flag)
400 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
401 else {
402 tree_entry *current;
403 int j = 0;
405 current = tree->selected_ptr;
406 while (j < i && current->next
407 && current->next->sublevel >= tree->selected_ptr->sublevel){
408 current = current->next;
409 if (current->sublevel == tree->selected_ptr->sublevel){
410 tree->selected_ptr = current;
411 j ++;
414 i = j;
417 tree->topdiff += i;
418 tree_check_focus (tree);
421 static void
422 tree_move_to_child (WTree *tree)
424 tree_entry *current;
426 /* Do we have a starting point? */
427 if (!tree->selected_ptr)
428 return;
429 /* Take the next entry */
430 current = tree->selected_ptr->next;
431 /* Is it the child of the selected entry */
432 if (current && current->sublevel > tree->selected_ptr->sublevel){
433 /* Yes -> select this entry */
434 tree->selected_ptr = current;
435 tree->topdiff++;
436 tree_check_focus (tree);
437 } else {
438 /* No -> rescan and try again */
439 tree_rescan (tree);
440 current = tree->selected_ptr->next;
441 if (current && current->sublevel > tree->selected_ptr->sublevel){
442 tree->selected_ptr = current;
443 tree->topdiff++;
444 tree_check_focus (tree);
449 static gboolean
450 tree_move_to_parent (WTree *tree)
452 tree_entry *current;
453 tree_entry *old;
455 if (!tree->selected_ptr)
456 return FALSE;
458 old = tree->selected_ptr;
459 current = tree->selected_ptr->prev;
460 while (current && current->sublevel >= tree->selected_ptr->sublevel){
461 current = current->prev;
462 tree->topdiff--;
464 if (!current)
465 current = tree->store->tree_first;
466 tree->selected_ptr = current;
467 tree_check_focus (tree);
468 return tree->selected_ptr != old;
471 static void
472 tree_move_to_top (WTree *tree)
474 tree->selected_ptr = tree->store->tree_first;
475 tree->topdiff = 0;
478 static void
479 tree_move_to_bottom (WTree *tree)
481 tree->selected_ptr = tree->store->tree_last;
482 tree->topdiff = tlines (tree) - 3 - 1;
485 /* Handle mouse click */
486 static void
487 tree_event (WTree *tree, int y)
489 if (tree->tree_shown [y]){
490 tree->selected_ptr = tree->tree_shown [y];
491 tree->topdiff = y;
493 show_tree (tree);
496 static void
497 tree_chdir_sel (WTree *tree)
499 if (!tree->is_panel)
500 return;
502 change_panel ();
504 if (do_cd (tree->selected_ptr->name, cd_exact))
505 select_item (current_panel);
506 else
507 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
508 tree->selected_ptr->name, unix_error_string (errno));
510 change_panel ();
511 show_tree (tree);
514 static void
515 maybe_chdir (WTree *tree)
517 if (xtree_mode && tree->is_panel && is_idle ())
518 tree_chdir_sel (tree);
521 /* Mouse callback */
522 static int
523 event_callback (Gpm_Event *event, void *data)
525 WTree *tree = data;
527 /* rest of the upper frame, the menu is invisible - call menu */
528 if (tree->is_panel && (event->type & GPM_DOWN)
529 && event->y == 1 && !menubar_visible) {
530 event->x += tree->widget.x;
531 return the_menubar->widget.mouse (event, the_menubar);
534 if (!(event->type & GPM_UP))
535 return MOU_NORMAL;
537 if (tree->is_panel)
538 event->y--;
540 event->y--;
542 if (!tree->active)
543 change_panel ();
545 if (event->y < 0){
546 tree_move_backward (tree, tlines (tree) - 1);
547 show_tree (tree);
548 } else if (event->y >= tlines (tree)){
549 tree_move_forward (tree, tlines (tree) - 1);
550 show_tree (tree);
551 } else {
552 tree_event (tree, event->y);
553 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
554 tree_chdir_sel (tree);
557 return MOU_NORMAL;
560 /* Search tree for text */
561 static int
562 search_tree (WTree *tree, char *text)
564 tree_entry *current;
565 int len;
566 int wrapped = 0;
567 int found = 0;
569 len = strlen (text);
570 current = tree->selected_ptr;
571 found = 0;
572 while (!wrapped || current != tree->selected_ptr){
573 if (strncmp (current->subname, text, len) == 0){
574 tree->selected_ptr = current;
575 found = 1;
576 break;
578 current = current->next;
579 if (!current){
580 current = tree->store->tree_first;
581 wrapped = 1;
583 tree->topdiff++;
585 tree_check_focus (tree);
586 return found;
589 static void
590 tree_do_search (WTree *tree, int key)
592 size_t l;
594 l = strlen (tree->search_buffer);
595 if ((l != 0) && (key == KEY_BACKSPACE))
596 tree->search_buffer [--l] = '\0';
597 else if (key && l < sizeof (tree->search_buffer)){
598 tree->search_buffer [l] = key;
599 tree->search_buffer [++l] = '\0';
602 if (!search_tree (tree, tree->search_buffer))
603 tree->search_buffer [--l] = 0;
605 show_tree (tree);
606 maybe_chdir (tree);
609 static void
610 tree_rescan (void *data)
612 char old_dir [MC_MAXPATHLEN];
613 WTree *tree = data;
615 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
616 mc_chdir (tree->selected_ptr->name))
617 return;
619 tree_store_rescan (tree->selected_ptr->name);
620 mc_chdir (old_dir);
623 static void
624 tree_forget (void *data)
626 WTree *tree = data;
627 if (tree->selected_ptr)
628 tree_remove_entry (tree, tree->selected_ptr->name);
631 static void
632 tree_copy (WTree *tree, const char *default_dest)
634 char msg [BUF_MEDIUM];
635 char *dest;
636 off_t count = 0;
637 double bytes = 0;
638 FileOpContext *ctx;
640 if (tree->selected_ptr == NULL)
641 return;
643 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
644 str_trunc (tree->selected_ptr->name, 50));
645 dest = input_expand_dialog (Q_("DialogTitle|Copy"), msg, MC_HISTORY_FM_TREE_COPY, default_dest);
647 if (dest != NULL && *dest != '\0') {
648 ctx = file_op_context_new (OP_COPY);
649 file_op_context_create_ui (ctx, FALSE);
650 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
651 file_op_context_destroy (ctx);
654 g_free (dest);
657 static void
658 tree_move (WTree *tree, const char *default_dest)
660 char msg [BUF_MEDIUM];
661 char *dest;
662 struct stat buf;
663 double bytes = 0;
664 off_t count = 0;
665 FileOpContext *ctx;
667 if (tree->selected_ptr == NULL)
668 return;
670 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
671 str_trunc (tree->selected_ptr->name, 50));
672 dest = input_expand_dialog (Q_("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
674 if (dest == NULL || *dest == '\0') {
675 g_free (dest);
676 return;
679 if (stat (dest, &buf)){
680 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
681 unix_error_string (errno));
682 g_free (dest);
683 return;
686 if (!S_ISDIR (buf.st_mode)){
687 file_error (_(" Destination \"%s\" must be a directory \n %s "),
688 dest);
689 g_free (dest);
690 return;
693 ctx = file_op_context_new (OP_MOVE);
694 file_op_context_create_ui (ctx, FALSE);
695 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
696 file_op_context_destroy (ctx);
698 g_free (dest);
701 #if 0
702 static void
703 tree_mkdir (WTree *tree)
705 char old_dir [MC_MAXPATHLEN];
707 if (!tree->selected_ptr)
708 return;
709 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
710 return;
711 if (chdir (tree->selected_ptr->name))
712 return;
713 /* FIXME
714 mkdir_cmd (tree);
716 tree_rescan (tree);
717 chdir (old_dir);
719 #endif
721 static void
722 tree_rmdir (void *data)
724 WTree *tree = data;
725 off_t count = 0;
726 double bytes = 0;
727 FileOpContext *ctx;
729 if (!tree->selected_ptr)
730 return;
732 if (confirm_delete) {
733 char *buf;
734 int result;
736 buf =
737 g_strdup_printf (_(" Delete %s? "),
738 tree->selected_ptr->name);
739 result =
740 query_dialog (Q_("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
741 g_free (buf);
742 if (result != 0)
743 return;
746 ctx = file_op_context_new (OP_DELETE);
747 file_op_context_create_ui (ctx, FALSE);
748 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
749 tree_forget (tree);
750 file_op_context_destroy (ctx);
753 static inline void
754 tree_move_up (WTree *tree)
756 tree_move_backward (tree, 1);
757 show_tree (tree);
758 maybe_chdir (tree);
761 static inline void
762 tree_move_down (WTree *tree)
764 tree_move_forward (tree, 1);
765 show_tree (tree);
766 maybe_chdir (tree);
769 static inline void
770 tree_move_home (WTree *tree)
772 tree_move_to_top (tree);
773 show_tree (tree);
774 maybe_chdir (tree);
777 static inline void
778 tree_move_end (WTree *tree)
780 tree_move_to_bottom (tree);
781 show_tree (tree);
782 maybe_chdir (tree);
785 static void
786 tree_move_pgup (WTree *tree)
788 tree_move_backward (tree, tlines (tree) - 1);
789 show_tree (tree);
790 maybe_chdir (tree);
793 static void
794 tree_move_pgdn (WTree *tree)
796 tree_move_forward (tree, tlines (tree) - 1);
797 show_tree (tree);
798 maybe_chdir (tree);
801 static gboolean
802 tree_move_left (WTree *tree)
804 gboolean v = FALSE;
806 if (tree_navigation_flag) {
807 v = tree_move_to_parent (tree);
808 show_tree (tree);
809 maybe_chdir (tree);
812 return v;
815 static gboolean
816 tree_move_right (WTree *tree)
818 gboolean v = FALSE;
820 if (tree_navigation_flag) {
821 tree_move_to_child (tree);
822 show_tree (tree);
823 maybe_chdir (tree);
824 v = TRUE;
827 return v;
830 static void
831 tree_start_search (WTree *tree)
833 gboolean i;
835 if (tree->searching) {
836 if (tree->selected_ptr == tree->store->tree_last)
837 tree_move_to_top (tree);
838 else {
839 /* set navigation mode temporarily to 'Static' because in
840 * dynamic navigation mode tree_move_forward will not move
841 * to a lower sublevel if necessary (sequent searches must
842 * start with the directory followed the last found directory)
844 i = tree_navigation_flag;
845 tree_navigation_flag = 0;
846 tree_move_forward (tree, 1);
847 tree_navigation_flag = i;
849 tree_do_search (tree, 0);
850 } else {
851 tree->searching = 1;
852 tree->search_buffer[0] = 0;
856 static void
857 tree_toggle_navig (WTree *tree)
859 tree_navigation_flag = !tree_navigation_flag;
860 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
861 tree_navigation_flag ? Q_("ButtonBar|Static")
862 : Q_("ButtonBar|Dynamc"),
863 tree_map, (Widget *) tree);
866 static cb_ret_t
867 tree_execute_cmd (WTree *tree, unsigned long command)
869 cb_ret_t res = MSG_HANDLED;
871 if (command != CK_TreeStartSearch)
872 tree->searching = 0;
874 switch (command) {
875 case CK_TreeHelp:
876 interactive_display (NULL, "[Directory Tree]");
877 break;
878 case CK_TreeForget:
879 tree_forget (tree);
880 break;
881 case CK_TreeToggleNav:
882 tree_toggle_navig (tree);
883 break;
884 case CK_TreeCopy:
885 tree_copy (tree, "");
886 break;
887 case CK_TreeMove:
888 tree_move (tree, "");
889 break;
890 case CK_TreeMoveUp:
891 tree_move_up (tree);
892 break;
893 case CK_TreeMoveDown:
894 tree_move_down (tree);
895 break;
896 case CK_TreeMoveHome:
897 tree_move_home (tree);
898 break;
899 case CK_TreeMoveEnd:
900 tree_move_end (tree);
901 break;
902 case CK_TreeMovePgUp:
903 tree_move_pgup (tree);
904 break;
905 case CK_TreeMovePgDn:
906 tree_move_pgdn (tree);
907 break;
908 case CK_TreeOpen:
909 tree_chdir_sel (tree);
910 break;
911 case CK_TreeRescan:
912 tree_rescan (tree);
913 break;
914 case CK_TreeStartSearch:
915 tree_start_search (tree);
916 break;
917 case CK_TreeRemove:
918 tree_rmdir (tree);
919 break;
920 default:
921 res = MSG_NOT_HANDLED;
924 show_tree (tree);
926 return res;
929 static cb_ret_t
930 tree_key (WTree *tree, int key)
932 size_t i;
934 for (i = 0; tree_map [i].key != 0; i++)
935 if (key == tree_map [i].key)
936 switch (tree_map [i].command) {
937 case CK_TreeMoveLeft:
938 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
939 case CK_TreeMoveRight:
940 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
941 default:
942 tree_execute_cmd (tree, tree_map [i].command);
943 return MSG_HANDLED;
946 if (is_abort_char (key)) {
947 if (tree->is_panel) {
948 tree->searching = 0;
949 show_tree (tree);
950 return MSG_HANDLED; /* eat abort char */
952 /* modal tree dialog: let upper layer see the
953 abort character and close the dialog */
954 return MSG_NOT_HANDLED;
957 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
958 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
959 if (tree->searching){
960 tree_do_search (tree, key);
961 show_tree (tree);
962 return MSG_HANDLED;
965 if (!command_prompt) {
966 tree_start_search (tree);
967 tree_do_search (tree, key);
968 return MSG_HANDLED;
970 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
973 return MSG_NOT_HANDLED;
976 static void
977 tree_frame (Dlg_head *h, WTree *tree)
979 tty_setcolor (NORMAL_COLOR);
980 widget_erase ((Widget*) tree);
981 if (tree->is_panel) {
982 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
983 tree->widget.cols);
985 if (show_mini_info)
986 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
987 tree->widget.x + 1,
988 ACS_HLINE, tree->widget.cols - 2);
992 static cb_ret_t
993 tree_callback (Widget *w, widget_msg_t msg, int parm)
995 WTree *tree = (WTree *) w;
996 Dlg_head *h = tree->widget.parent;
997 WButtonBar *b = find_buttonbar (h);
999 switch (msg) {
1000 case WIDGET_DRAW:
1001 tree_frame (h, tree);
1002 show_tree (tree);
1003 return MSG_HANDLED;
1005 case WIDGET_FOCUS:
1006 tree->active = 1;
1007 buttonbar_set_label (b, 1, Q_("ButtonBar|Help"), tree_map, (Widget *) tree);
1008 buttonbar_set_label (b, 2, Q_("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1009 buttonbar_set_label (b, 3, Q_("ButtonBar|Forget"), tree_map, (Widget *) tree);
1010 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_("ButtonBar|Static")
1011 : Q_("ButtonBar|Dynamc"),
1012 tree_map, (Widget *) tree);
1013 buttonbar_set_label (b, 5, Q_("ButtonBar|Copy"), tree_map, (Widget *) tree);
1014 buttonbar_set_label (b, 6, Q_("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1015 #if 0
1016 /* FIXME: mkdir is currently defunct */
1017 buttonbar_set_label (b, 7, Q_("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1018 #else
1019 buttonbar_clear_label (b, 7, (Widget *) tree);
1020 #endif
1021 buttonbar_set_label (b, 8, Q_("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1022 buttonbar_redraw (b);
1024 /* FIXME: Should find a better way of only displaying the
1025 currently selected item */
1026 show_tree (tree);
1027 return MSG_HANDLED;
1029 /* FIXME: Should find a better way of changing the color of the
1030 selected item */
1032 case WIDGET_UNFOCUS:
1033 tree->active = 0;
1034 show_tree (tree);
1035 return MSG_HANDLED;
1037 case WIDGET_KEY:
1038 return tree_key (tree, parm);
1040 case WIDGET_COMMAND:
1041 /* command from buttonbar */
1042 return tree_execute_cmd (tree, parm);
1044 case WIDGET_DESTROY:
1045 tree_destroy (tree);
1046 return MSG_HANDLED;
1048 default:
1049 return default_proc (msg, parm);
1053 WTree *
1054 tree_new (int is_panel, int y, int x, int lines, int cols)
1056 WTree *tree = g_new (WTree, 1);
1058 init_widget (&tree->widget, y, x, lines, cols,
1059 tree_callback, event_callback);
1060 tree->is_panel = is_panel;
1061 tree->selected_ptr = 0;
1063 tree->store = tree_store_get ();
1064 tree_store_add_entry_remove_hook (remove_callback, tree);
1065 tree->tree_shown = 0;
1066 tree->search_buffer[0] = 0;
1067 tree->topdiff = tree->widget.lines / 2;
1068 tree->searching = 0;
1069 tree->active = 0;
1071 /* We do not want to keep the cursor */
1072 widget_want_cursor (tree->widget, 0);
1073 load_tree (tree);
1074 return tree;
1077 void
1078 tree_chdir (WTree *tree, const char *dir)
1080 tree_entry *current;
1082 current = tree_store_whereis (dir);
1084 if (current != NULL) {
1085 tree->selected_ptr = current;
1086 tree_check_focus (tree);
1090 /* Return name of the currently selected entry */
1091 char *
1092 tree_selected_name (const WTree *tree)
1094 return tree->selected_ptr->name;
1097 void
1098 sync_tree (const char *path)
1100 tree_chdir (the_tree, path);
1103 WTree *
1104 find_tree (struct Dlg_head *h)
1106 return (WTree *) find_widget_type (h, tree_callback);