Ticket #2212: fixed WTree widget colors.
[midnight-commander.git] / src / tree.c
blob2401659dc4fd9bc1eade68fcb1f7bce855600b05
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 "lib/global.h"
44 #include "lib/tty/tty.h"
45 #include "lib/skin.h"
46 #include "lib/tty/mouse.h"
47 #include "lib/tty/key.h"
48 #include "lib/vfs/mc-vfs/vfs.h"
49 #include "lib/fileloc.h"
50 #include "lib/strutil.h"
52 #include "wtools.h" /* message() */
53 #include "dir.h"
54 #include "dialog.h"
55 #include "widget.h"
56 #include "panel.h"
57 #include "main.h"
58 #include "main-widgets.h" /* the_menubar */
59 #include "menu.h" /* menubar_visible */
60 #include "file.h" /* copy_dir_dir(), move_dir_dir(), erase_dir() */
61 #include "layout.h" /* command_prompt */
62 #include "help.h"
63 #include "treestore.h"
64 #include "cmd.h"
65 #include "cmddef.h"
66 #include "keybind.h"
67 #include "history.h"
68 #include "tree.h"
70 const global_keymap_t *tree_map;
72 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (show_mini_info ? 2 : 0) : t->widget.lines)
74 /* Use the color of the parent widget for the unselected entries */
75 #define TREE_NORMALC(h) (DLG_NORMALC (h))
76 #define TREE_CURRENTC(h) (DLG_FOCUSC (h))
78 /* Specifies the display mode: 1d or 2d */
79 static gboolean tree_navigation_flag = FALSE;
81 struct WTree {
82 Widget widget;
83 struct TreeStore *store;
84 tree_entry *selected_ptr; /* The selected directory */
85 char search_buffer[256]; /* Current search string */
86 tree_entry **tree_shown; /* Entries currently on screen */
87 int is_panel; /* panel or plain widget flag */
88 int active; /* if it's currently selected */
89 int searching; /* Are we on searching mode? */
90 int topdiff; /* The difference between the topmost
91 shown and the selected */
94 /* Forwards */
95 static void tree_rescan (void *data);
97 static tree_entry *
98 back_ptr (tree_entry *ptr, int *count)
100 int i = 0;
102 while (ptr && ptr->prev && i < *count){
103 ptr = ptr->prev;
104 i ++;
106 *count = i;
107 return ptr;
110 static tree_entry *
111 forw_ptr (tree_entry *ptr, int *count)
113 int i = 0;
115 while (ptr && ptr->next && i < *count){
116 ptr = ptr->next;
117 i ++;
119 *count = i;
120 return ptr;
123 static void
124 remove_callback (tree_entry *entry, void *data)
126 WTree *tree = data;
128 if (tree->selected_ptr == entry){
129 if (tree->selected_ptr->next)
130 tree->selected_ptr = tree->selected_ptr->next;
131 else
132 tree->selected_ptr = tree->selected_ptr->prev;
136 /* Save the ~/.mc/Tree file */
137 static void
138 save_tree (WTree *tree)
140 int error;
141 char *tree_name;
143 (void) tree;
144 error = tree_store_save ();
147 if (error){
148 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR,
149 MC_TREESTORE_FILE, (char *) NULL);
150 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
151 unix_error_string (error));
152 g_free (tree_name);
156 static void
157 tree_remove_entry (WTree *tree, char *name)
159 (void) tree;
160 tree_store_remove_entry (name);
163 static void
164 tree_destroy (WTree *tree)
166 tree_store_remove_entry_remove_hook (remove_callback);
167 save_tree (tree);
169 g_free (tree->tree_shown);
170 tree->tree_shown = 0;
171 tree->selected_ptr = NULL;
174 /* Loads the .mc.tree file */
175 static void
176 load_tree (WTree *tree)
178 tree_store_load ();
180 tree->selected_ptr = tree->store->tree_first;
181 tree_chdir (tree, home_dir);
184 static void
185 tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
187 Dlg_head *h = tree->widget.parent;
188 int line;
190 /* Show mini info */
191 if (tree->is_panel){
192 if (!show_mini_info)
193 return;
194 line = tree_lines+2;
195 } else
196 line = tree_lines+1;
198 if (tree->searching)
200 /* Show search string */
201 tty_setcolor (INPUT_COLOR);
202 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
203 widget_move (&tree->widget, line, 1);
204 tty_print_char (PATH_SEP);
205 tty_print_string (str_fit_to_term (tree->search_buffer, tree_cols - 2, J_LEFT_FIT));
206 tty_print_char (' ');
208 else
210 /* Show full name of selected directory */
211 tty_setcolor (tree->is_panel ? NORMAL_COLOR : TREE_NORMALC (h));
212 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
213 widget_move (&tree->widget, line, 1);
214 tty_print_string (str_fit_to_term (tree->selected_ptr->name, tree_cols, J_LEFT_FIT));
218 static void
219 show_tree (WTree *tree)
221 Dlg_head *h = tree->widget.parent;
222 tree_entry *current;
223 int i, j, topsublevel;
224 int x, y;
225 int tree_lines, tree_cols;
227 /* Initialize */
228 x = y = 0;
229 tree_lines = tlines (tree);
230 tree_cols = tree->widget.cols;
232 widget_move ((Widget *) tree, y, x);
233 if (tree->is_panel)
235 tree_cols -= 2;
236 x = y = 1;
239 g_free (tree->tree_shown);
240 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
242 if (tree->store->tree_first)
243 topsublevel = tree->store->tree_first->sublevel;
244 else
245 topsublevel = 0;
246 if (!tree->selected_ptr){
247 tree->selected_ptr = tree->store->tree_first;
248 tree->topdiff = 0;
250 current = tree->selected_ptr;
252 /* Calculate the directory which is to be shown on the topmost line */
253 if (!tree_navigation_flag)
254 current = back_ptr (current, &tree->topdiff);
255 else {
256 i = 0;
257 while (current->prev && i < tree->topdiff){
258 current = current->prev;
259 if (current->sublevel < tree->selected_ptr->sublevel){
260 if (strncmp (current->name, tree->selected_ptr->name,
261 strlen (current->name)) == 0)
262 i++;
263 } else if (current->sublevel == tree->selected_ptr->sublevel){
264 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
265 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
266 i++;
267 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
268 && strlen (tree->selected_ptr->name) > 1){
269 if (strncmp (current->name, tree->selected_ptr->name,
270 strlen (tree->selected_ptr->name)) == 0)
271 i++;
274 tree->topdiff = i;
277 /* Loop for every line */
278 for (i = 0; i < tree_lines; i++)
280 tty_setcolor (tree->is_panel ? NORMAL_COLOR : TREE_NORMALC (h));
282 /* Move to the beginning of the line */
283 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x, ' ', tree_cols);
285 if (current == NULL)
286 continue;
288 if (tree->is_panel)
289 tty_setcolor (tree->active && current == tree->selected_ptr
290 ? SELECTED_COLOR : NORMAL_COLOR);
291 else
292 tty_setcolor (current == tree->selected_ptr ? TREE_CURRENTC (h) : TREE_NORMALC (h));
294 tree->tree_shown[i] = current;
295 if (current->sublevel == topsublevel)
297 /* Show full name */
298 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
300 else
302 /* Sub level directory */
303 tty_set_alt_charset (TRUE);
305 /* Output branch parts */
306 for (j = 0; j < current->sublevel - topsublevel - 1; j++)
308 if (tree_cols - 8 - 3 * j < 9)
309 break;
310 tty_print_char (' ');
311 if (current->submask & (1 << (j + topsublevel + 1)))
312 tty_print_char (ACS_VLINE);
313 else
314 tty_print_char (' ');
315 tty_print_char (' ');
317 tty_print_char (' ');
318 j++;
319 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
320 tty_print_char (ACS_LLCORNER);
321 else
322 tty_print_char (ACS_LTEE);
323 tty_print_char (ACS_HLINE);
324 tty_set_alt_charset (FALSE);
326 /* Show sub-name */
327 tty_print_char (' ');
328 tty_print_string (str_fit_to_term (current->subname,
329 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
331 tty_print_char (' ');
334 /* Calculate the next value for current */
335 current = current->next;
336 if (tree_navigation_flag)
338 while (current != NULL)
340 if (current->sublevel < tree->selected_ptr->sublevel)
342 if (strncmp (current->name, tree->selected_ptr->name,
343 strlen (current->name)) == 0)
344 break;
346 else if (current->sublevel == tree->selected_ptr->sublevel)
348 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--)
350 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
351 break;
353 else if (current->sublevel == tree->selected_ptr->sublevel + 1
354 && strlen (tree->selected_ptr->name) > 1)
356 if (strncmp (current->name, tree->selected_ptr->name,
357 strlen (tree->selected_ptr->name)) == 0)
358 break;
360 current = current->next;
365 tree_show_mini_info (tree, tree_lines, tree_cols);
368 static void
369 tree_check_focus (WTree *tree)
371 if (tree->topdiff < 3)
372 tree->topdiff = 3;
373 else if (tree->topdiff >= tlines (tree) - 3)
374 tree->topdiff = tlines (tree) - 3 - 1;
377 static void
378 tree_move_backward (WTree *tree, int i)
380 if (!tree_navigation_flag)
381 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
382 else {
383 tree_entry *current;
384 int j = 0;
386 current = tree->selected_ptr;
387 while (j < i && current->prev
388 && current->prev->sublevel >= tree->selected_ptr->sublevel){
389 current = current->prev;
390 if (current->sublevel == tree->selected_ptr->sublevel){
391 tree->selected_ptr = current;
392 j++;
395 i = j;
398 tree->topdiff -= i;
399 tree_check_focus (tree);
402 static void
403 tree_move_forward (WTree *tree, int i)
405 if (!tree_navigation_flag)
406 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
407 else {
408 tree_entry *current;
409 int j = 0;
411 current = tree->selected_ptr;
412 while (j < i && current->next
413 && current->next->sublevel >= tree->selected_ptr->sublevel){
414 current = current->next;
415 if (current->sublevel == tree->selected_ptr->sublevel){
416 tree->selected_ptr = current;
417 j ++;
420 i = j;
423 tree->topdiff += i;
424 tree_check_focus (tree);
427 static void
428 tree_move_to_child (WTree *tree)
430 tree_entry *current;
432 /* Do we have a starting point? */
433 if (!tree->selected_ptr)
434 return;
435 /* Take the next entry */
436 current = tree->selected_ptr->next;
437 /* Is it the child of the selected entry */
438 if (current && current->sublevel > tree->selected_ptr->sublevel){
439 /* Yes -> select this entry */
440 tree->selected_ptr = current;
441 tree->topdiff++;
442 tree_check_focus (tree);
443 } else {
444 /* No -> rescan and try again */
445 tree_rescan (tree);
446 current = tree->selected_ptr->next;
447 if (current && current->sublevel > tree->selected_ptr->sublevel){
448 tree->selected_ptr = current;
449 tree->topdiff++;
450 tree_check_focus (tree);
455 static gboolean
456 tree_move_to_parent (WTree *tree)
458 tree_entry *current;
459 tree_entry *old;
461 if (!tree->selected_ptr)
462 return FALSE;
464 old = tree->selected_ptr;
465 current = tree->selected_ptr->prev;
466 while (current && current->sublevel >= tree->selected_ptr->sublevel){
467 current = current->prev;
468 tree->topdiff--;
470 if (!current)
471 current = tree->store->tree_first;
472 tree->selected_ptr = current;
473 tree_check_focus (tree);
474 return tree->selected_ptr != old;
477 static void
478 tree_move_to_top (WTree *tree)
480 tree->selected_ptr = tree->store->tree_first;
481 tree->topdiff = 0;
484 static void
485 tree_move_to_bottom (WTree *tree)
487 tree->selected_ptr = tree->store->tree_last;
488 tree->topdiff = tlines (tree) - 3 - 1;
491 /* Handle mouse click */
492 static void
493 tree_event (WTree *tree, int y)
495 if (tree->tree_shown [y]){
496 tree->selected_ptr = tree->tree_shown [y];
497 tree->topdiff = y;
499 show_tree (tree);
502 static void
503 tree_chdir_sel (WTree *tree)
505 if (!tree->is_panel)
506 return;
508 change_panel ();
510 if (do_cd (tree->selected_ptr->name, cd_exact))
511 select_item (current_panel);
512 else
513 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
514 tree->selected_ptr->name, unix_error_string (errno));
516 change_panel ();
517 show_tree (tree);
520 static void
521 maybe_chdir (WTree *tree)
523 if (xtree_mode && tree->is_panel && is_idle ())
524 tree_chdir_sel (tree);
527 /* Mouse callback */
528 static int
529 event_callback (Gpm_Event *event, void *data)
531 WTree *tree = data;
533 /* rest of the upper frame, the menu is invisible - call menu */
534 if (tree->is_panel && (event->type & GPM_DOWN)
535 && event->y == 1 && !menubar_visible) {
536 event->x += tree->widget.x;
537 return the_menubar->widget.mouse (event, the_menubar);
540 if (!(event->type & GPM_UP))
541 return MOU_NORMAL;
543 if (tree->is_panel)
544 event->y--;
546 event->y--;
548 if (!tree->active)
549 change_panel ();
551 if (event->y < 0){
552 tree_move_backward (tree, tlines (tree) - 1);
553 show_tree (tree);
554 } else if (event->y >= tlines (tree)){
555 tree_move_forward (tree, tlines (tree) - 1);
556 show_tree (tree);
557 } else {
558 tree_event (tree, event->y);
559 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
560 tree_chdir_sel (tree);
563 return MOU_NORMAL;
566 /* Search tree for text */
567 static int
568 search_tree (WTree *tree, char *text)
570 tree_entry *current;
571 int len;
572 int wrapped = 0;
573 int found = 0;
575 len = strlen (text);
576 current = tree->selected_ptr;
577 found = 0;
578 while (!wrapped || current != tree->selected_ptr){
579 if (strncmp (current->subname, text, len) == 0){
580 tree->selected_ptr = current;
581 found = 1;
582 break;
584 current = current->next;
585 if (!current){
586 current = tree->store->tree_first;
587 wrapped = 1;
589 tree->topdiff++;
591 tree_check_focus (tree);
592 return found;
595 static void
596 tree_do_search (WTree *tree, int key)
598 size_t l;
600 l = strlen (tree->search_buffer);
601 if ((l != 0) && (key == KEY_BACKSPACE))
602 tree->search_buffer [--l] = '\0';
603 else if (key && l < sizeof (tree->search_buffer)){
604 tree->search_buffer [l] = key;
605 tree->search_buffer [++l] = '\0';
608 if (!search_tree (tree, tree->search_buffer))
609 tree->search_buffer [--l] = 0;
611 show_tree (tree);
612 maybe_chdir (tree);
615 static void
616 tree_rescan (void *data)
618 char old_dir [MC_MAXPATHLEN];
619 WTree *tree = data;
621 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
622 mc_chdir (tree->selected_ptr->name))
623 return;
625 tree_store_rescan (tree->selected_ptr->name);
626 mc_chdir (old_dir);
629 static void
630 tree_forget (void *data)
632 WTree *tree = data;
633 if (tree->selected_ptr)
634 tree_remove_entry (tree, tree->selected_ptr->name);
637 static void
638 tree_copy (WTree *tree, const char *default_dest)
640 char msg [BUF_MEDIUM];
641 char *dest;
642 off_t count = 0;
643 double bytes = 0;
644 FileOpContext *ctx;
646 if (tree->selected_ptr == NULL)
647 return;
649 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
650 str_trunc (tree->selected_ptr->name, 50));
651 dest = input_expand_dialog (Q_("DialogTitle|Copy"), msg, MC_HISTORY_FM_TREE_COPY, default_dest);
653 if (dest != NULL && *dest != '\0') {
654 ctx = file_op_context_new (OP_COPY);
655 file_op_context_create_ui (ctx, FALSE);
656 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
657 file_op_context_destroy (ctx);
660 g_free (dest);
663 static void
664 tree_move (WTree *tree, const char *default_dest)
666 char msg [BUF_MEDIUM];
667 char *dest;
668 struct stat buf;
669 double bytes = 0;
670 off_t count = 0;
671 FileOpContext *ctx;
673 if (tree->selected_ptr == NULL)
674 return;
676 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
677 str_trunc (tree->selected_ptr->name, 50));
678 dest = input_expand_dialog (Q_("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
680 if (dest == NULL || *dest == '\0') {
681 g_free (dest);
682 return;
685 if (stat (dest, &buf)){
686 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
687 unix_error_string (errno));
688 g_free (dest);
689 return;
692 if (!S_ISDIR (buf.st_mode)){
693 file_error (_(" Destination \"%s\" must be a directory \n %s "),
694 dest);
695 g_free (dest);
696 return;
699 ctx = file_op_context_new (OP_MOVE);
700 file_op_context_create_ui (ctx, FALSE);
701 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
702 file_op_context_destroy (ctx);
704 g_free (dest);
707 #if 0
708 static void
709 tree_mkdir (WTree *tree)
711 char old_dir [MC_MAXPATHLEN];
713 if (!tree->selected_ptr)
714 return;
715 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
716 return;
717 if (chdir (tree->selected_ptr->name))
718 return;
719 /* FIXME
720 mkdir_cmd (tree);
722 tree_rescan (tree);
723 chdir (old_dir);
725 #endif
727 static void
728 tree_rmdir (void *data)
730 WTree *tree = data;
731 off_t count = 0;
732 double bytes = 0;
733 FileOpContext *ctx;
735 if (!tree->selected_ptr)
736 return;
738 if (confirm_delete) {
739 char *buf;
740 int result;
742 buf =
743 g_strdup_printf (_(" Delete %s? "),
744 tree->selected_ptr->name);
745 result =
746 query_dialog (Q_("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
747 g_free (buf);
748 if (result != 0)
749 return;
752 ctx = file_op_context_new (OP_DELETE);
753 file_op_context_create_ui (ctx, FALSE);
754 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
755 tree_forget (tree);
756 file_op_context_destroy (ctx);
759 static inline void
760 tree_move_up (WTree *tree)
762 tree_move_backward (tree, 1);
763 show_tree (tree);
764 maybe_chdir (tree);
767 static inline void
768 tree_move_down (WTree *tree)
770 tree_move_forward (tree, 1);
771 show_tree (tree);
772 maybe_chdir (tree);
775 static inline void
776 tree_move_home (WTree *tree)
778 tree_move_to_top (tree);
779 show_tree (tree);
780 maybe_chdir (tree);
783 static inline void
784 tree_move_end (WTree *tree)
786 tree_move_to_bottom (tree);
787 show_tree (tree);
788 maybe_chdir (tree);
791 static void
792 tree_move_pgup (WTree *tree)
794 tree_move_backward (tree, tlines (tree) - 1);
795 show_tree (tree);
796 maybe_chdir (tree);
799 static void
800 tree_move_pgdn (WTree *tree)
802 tree_move_forward (tree, tlines (tree) - 1);
803 show_tree (tree);
804 maybe_chdir (tree);
807 static gboolean
808 tree_move_left (WTree *tree)
810 gboolean v = FALSE;
812 if (tree_navigation_flag) {
813 v = tree_move_to_parent (tree);
814 show_tree (tree);
815 maybe_chdir (tree);
818 return v;
821 static gboolean
822 tree_move_right (WTree *tree)
824 gboolean v = FALSE;
826 if (tree_navigation_flag) {
827 tree_move_to_child (tree);
828 show_tree (tree);
829 maybe_chdir (tree);
830 v = TRUE;
833 return v;
836 static void
837 tree_start_search (WTree *tree)
839 gboolean i;
841 if (tree->searching) {
842 if (tree->selected_ptr == tree->store->tree_last)
843 tree_move_to_top (tree);
844 else {
845 /* set navigation mode temporarily to 'Static' because in
846 * dynamic navigation mode tree_move_forward will not move
847 * to a lower sublevel if necessary (sequent searches must
848 * start with the directory followed the last found directory)
850 i = tree_navigation_flag;
851 tree_navigation_flag = 0;
852 tree_move_forward (tree, 1);
853 tree_navigation_flag = i;
855 tree_do_search (tree, 0);
856 } else {
857 tree->searching = 1;
858 tree->search_buffer[0] = 0;
862 static void
863 tree_toggle_navig (WTree *tree)
865 tree_navigation_flag = !tree_navigation_flag;
866 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
867 tree_navigation_flag ? Q_("ButtonBar|Static")
868 : Q_("ButtonBar|Dynamc"),
869 tree_map, (Widget *) tree);
872 static cb_ret_t
873 tree_execute_cmd (WTree *tree, unsigned long command)
875 cb_ret_t res = MSG_HANDLED;
877 if (command != CK_TreeStartSearch)
878 tree->searching = 0;
880 switch (command) {
881 case CK_TreeHelp:
882 interactive_display (NULL, "[Directory Tree]");
883 break;
884 case CK_TreeForget:
885 tree_forget (tree);
886 break;
887 case CK_TreeToggleNav:
888 tree_toggle_navig (tree);
889 break;
890 case CK_TreeCopy:
891 tree_copy (tree, "");
892 break;
893 case CK_TreeMove:
894 tree_move (tree, "");
895 break;
896 case CK_TreeMoveUp:
897 tree_move_up (tree);
898 break;
899 case CK_TreeMoveDown:
900 tree_move_down (tree);
901 break;
902 case CK_TreeMoveHome:
903 tree_move_home (tree);
904 break;
905 case CK_TreeMoveEnd:
906 tree_move_end (tree);
907 break;
908 case CK_TreeMovePgUp:
909 tree_move_pgup (tree);
910 break;
911 case CK_TreeMovePgDn:
912 tree_move_pgdn (tree);
913 break;
914 case CK_TreeOpen:
915 tree_chdir_sel (tree);
916 break;
917 case CK_TreeRescan:
918 tree_rescan (tree);
919 break;
920 case CK_TreeStartSearch:
921 tree_start_search (tree);
922 break;
923 case CK_TreeRemove:
924 tree_rmdir (tree);
925 break;
926 default:
927 res = MSG_NOT_HANDLED;
930 show_tree (tree);
932 return res;
935 static cb_ret_t
936 tree_key (WTree *tree, int key)
938 size_t i;
940 for (i = 0; tree_map [i].key != 0; i++)
941 if (key == tree_map [i].key)
942 switch (tree_map [i].command) {
943 case CK_TreeMoveLeft:
944 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
945 case CK_TreeMoveRight:
946 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
947 default:
948 tree_execute_cmd (tree, tree_map [i].command);
949 return MSG_HANDLED;
952 if (is_abort_char (key)) {
953 if (tree->is_panel) {
954 tree->searching = 0;
955 show_tree (tree);
956 return MSG_HANDLED; /* eat abort char */
958 /* modal tree dialog: let upper layer see the
959 abort character and close the dialog */
960 return MSG_NOT_HANDLED;
963 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
964 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
965 if (tree->searching){
966 tree_do_search (tree, key);
967 show_tree (tree);
968 return MSG_HANDLED;
971 if (!command_prompt) {
972 tree_start_search (tree);
973 tree_do_search (tree, key);
974 return MSG_HANDLED;
976 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
979 return MSG_NOT_HANDLED;
982 static void
983 tree_frame (Dlg_head *h, WTree *tree)
985 tty_setcolor (NORMAL_COLOR);
986 widget_erase ((Widget*) tree);
987 if (tree->is_panel) {
988 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
989 tree->widget.cols);
991 if (show_mini_info)
992 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
993 tree->widget.x + 1,
994 ACS_HLINE, tree->widget.cols - 2);
998 static cb_ret_t
999 tree_callback (Widget *w, widget_msg_t msg, int parm)
1001 WTree *tree = (WTree *) w;
1002 Dlg_head *h = tree->widget.parent;
1003 WButtonBar *b = find_buttonbar (h);
1005 switch (msg) {
1006 case WIDGET_DRAW:
1007 tree_frame (h, tree);
1008 show_tree (tree);
1009 return MSG_HANDLED;
1011 case WIDGET_FOCUS:
1012 tree->active = 1;
1013 buttonbar_set_label (b, 1, Q_("ButtonBar|Help"), tree_map, (Widget *) tree);
1014 buttonbar_set_label (b, 2, Q_("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1015 buttonbar_set_label (b, 3, Q_("ButtonBar|Forget"), tree_map, (Widget *) tree);
1016 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_("ButtonBar|Static")
1017 : Q_("ButtonBar|Dynamc"),
1018 tree_map, (Widget *) tree);
1019 buttonbar_set_label (b, 5, Q_("ButtonBar|Copy"), tree_map, (Widget *) tree);
1020 buttonbar_set_label (b, 6, Q_("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1021 #if 0
1022 /* FIXME: mkdir is currently defunct */
1023 buttonbar_set_label (b, 7, Q_("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1024 #else
1025 buttonbar_clear_label (b, 7, (Widget *) tree);
1026 #endif
1027 buttonbar_set_label (b, 8, Q_("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1028 buttonbar_redraw (b);
1030 /* FIXME: Should find a better way of only displaying the
1031 currently selected item */
1032 show_tree (tree);
1033 return MSG_HANDLED;
1035 /* FIXME: Should find a better way of changing the color of the
1036 selected item */
1038 case WIDGET_UNFOCUS:
1039 tree->active = 0;
1040 show_tree (tree);
1041 return MSG_HANDLED;
1043 case WIDGET_KEY:
1044 return tree_key (tree, parm);
1046 case WIDGET_COMMAND:
1047 /* command from buttonbar */
1048 return tree_execute_cmd (tree, parm);
1050 case WIDGET_DESTROY:
1051 tree_destroy (tree);
1052 return MSG_HANDLED;
1054 default:
1055 return default_proc (msg, parm);
1059 WTree *
1060 tree_new (int is_panel, int y, int x, int lines, int cols)
1062 WTree *tree = g_new (WTree, 1);
1064 init_widget (&tree->widget, y, x, lines, cols,
1065 tree_callback, event_callback);
1066 tree->is_panel = is_panel;
1067 tree->selected_ptr = 0;
1069 tree->store = tree_store_get ();
1070 tree_store_add_entry_remove_hook (remove_callback, tree);
1071 tree->tree_shown = 0;
1072 tree->search_buffer[0] = 0;
1073 tree->topdiff = tree->widget.lines / 2;
1074 tree->searching = 0;
1075 tree->active = 0;
1077 /* We do not want to keep the cursor */
1078 widget_want_cursor (tree->widget, 0);
1079 load_tree (tree);
1080 return tree;
1083 void
1084 tree_chdir (WTree *tree, const char *dir)
1086 tree_entry *current;
1088 current = tree_store_whereis (dir);
1090 if (current != NULL) {
1091 tree->selected_ptr = current;
1092 tree_check_focus (tree);
1096 /* Return name of the currently selected entry */
1097 char *
1098 tree_selected_name (const WTree *tree)
1100 return tree->selected_ptr->name;
1103 void
1104 sync_tree (const char *path)
1106 tree_chdir (the_tree, path);
1109 WTree *
1110 find_tree (struct Dlg_head *h)
1112 return (WTree *) find_widget_type (h, tree_callback);