Merge branch '1981_AM_PROG_CC_C_O'
[midnight-commander.git] / src / tree.c
blob8ab1d140306c5849a0639d481b8442b6a312daa1
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))
77 /* Specifies the display mode: 1d or 2d */
78 static gboolean tree_navigation_flag = FALSE;
80 struct WTree {
81 Widget widget;
82 struct TreeStore *store;
83 tree_entry *selected_ptr; /* The selected directory */
84 char search_buffer[256]; /* Current search string */
85 tree_entry **tree_shown; /* Entries currently on screen */
86 int is_panel; /* panel or plain widget flag */
87 int active; /* if it's currently selected */
88 int searching; /* Are we on searching mode? */
89 int topdiff; /* The difference between the topmost
90 shown and the selected */
93 /* Forwards */
94 static void tree_rescan (void *data);
96 static tree_entry *
97 back_ptr (tree_entry *ptr, int *count)
99 int i = 0;
101 while (ptr && ptr->prev && i < *count){
102 ptr = ptr->prev;
103 i ++;
105 *count = i;
106 return ptr;
109 static tree_entry *
110 forw_ptr (tree_entry *ptr, int *count)
112 int i = 0;
114 while (ptr && ptr->next && i < *count){
115 ptr = ptr->next;
116 i ++;
118 *count = i;
119 return ptr;
122 static void
123 remove_callback (tree_entry *entry, void *data)
125 WTree *tree = data;
127 if (tree->selected_ptr == entry){
128 if (tree->selected_ptr->next)
129 tree->selected_ptr = tree->selected_ptr->next;
130 else
131 tree->selected_ptr = tree->selected_ptr->prev;
135 /* Save the ~/.mc/Tree file */
136 static void
137 save_tree (WTree *tree)
139 int error;
140 char *tree_name;
142 (void) tree;
143 error = tree_store_save ();
146 if (error){
147 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR,
148 MC_TREESTORE_FILE, (char *) NULL);
149 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
150 unix_error_string (error));
151 g_free (tree_name);
155 static void
156 tree_remove_entry (WTree *tree, char *name)
158 (void) tree;
159 tree_store_remove_entry (name);
162 static void
163 tree_destroy (WTree *tree)
165 tree_store_remove_entry_remove_hook (remove_callback);
166 save_tree (tree);
168 g_free (tree->tree_shown);
169 tree->tree_shown = 0;
170 tree->selected_ptr = NULL;
173 /* Loads the .mc.tree file */
174 static void
175 load_tree (WTree *tree)
177 tree_store_load ();
179 tree->selected_ptr = tree->store->tree_first;
180 tree_chdir (tree, home_dir);
183 static void
184 tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
186 Dlg_head *h = tree->widget.parent;
187 int line;
189 /* Show mini info */
190 if (tree->is_panel){
191 if (!show_mini_info)
192 return;
193 line = tree_lines+2;
194 } else
195 line = tree_lines+1;
197 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
198 widget_move (&tree->widget, line, 1);
200 if (tree->searching){
201 /* Show search string */
202 tty_setcolor (TREE_NORMALC (h));
203 tty_setcolor (DLG_FOCUSC (h));
204 tty_print_char (PATH_SEP);
206 tty_print_string (str_fit_to_term (tree->search_buffer,
207 tree_cols - 2, J_LEFT_FIT));
208 tty_print_char (' ');
209 tty_setcolor (DLG_FOCUSC (h));
210 } else {
211 /* Show full name of selected directory */
212 tty_print_string (str_fit_to_term (tree->selected_ptr->name,
213 tree_cols, J_LEFT_FIT));
217 static void
218 show_tree (WTree *tree)
220 Dlg_head *h = tree->widget.parent;
221 tree_entry *current;
222 int i, j, topsublevel;
223 int x, y;
224 int tree_lines, tree_cols;
226 /* Initialize */
227 x = y = 0;
228 tree_lines = tlines (tree);
229 tree_cols = tree->widget.cols;
231 tty_setcolor (TREE_NORMALC (h));
232 widget_move ((Widget*)tree, y, x);
233 if (tree->is_panel){
234 tree_cols -= 2;
235 x = y = 1;
238 g_free (tree->tree_shown);
239 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
241 if (tree->store->tree_first)
242 topsublevel = tree->store->tree_first->sublevel;
243 else
244 topsublevel = 0;
245 if (!tree->selected_ptr){
246 tree->selected_ptr = tree->store->tree_first;
247 tree->topdiff = 0;
249 current = tree->selected_ptr;
251 /* Calculate the directory which is to be shown on the topmost line */
252 if (!tree_navigation_flag)
253 current = back_ptr (current, &tree->topdiff);
254 else {
255 i = 0;
256 while (current->prev && i < tree->topdiff){
257 current = current->prev;
258 if (current->sublevel < tree->selected_ptr->sublevel){
259 if (strncmp (current->name, tree->selected_ptr->name,
260 strlen (current->name)) == 0)
261 i++;
262 } else if (current->sublevel == tree->selected_ptr->sublevel){
263 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
264 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
265 i++;
266 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
267 && strlen (tree->selected_ptr->name) > 1){
268 if (strncmp (current->name, tree->selected_ptr->name,
269 strlen (tree->selected_ptr->name)) == 0)
270 i++;
273 tree->topdiff = i;
276 /* Loop for every line */
277 for (i = 0; i < tree_lines; i++){
278 /* Move to the beginning of the line */
279 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x, ' ', tree_cols);
281 if (!current)
282 continue;
284 tree->tree_shown [i] = current;
285 if (current->sublevel == topsublevel){
287 /* Top level directory */
288 if (tree->active && current == tree->selected_ptr) {
289 if (!tty_use_colors () && !tree->is_panel)
290 tty_setcolor (MARKED_COLOR);
291 else
292 tty_setcolor (SELECTED_COLOR);
295 /* Show full name */
296 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
297 } else{
298 /* Sub level directory */
300 tty_set_alt_charset (TRUE);
301 /* Output branch parts */
302 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
303 if (tree_cols - 8 - 3 * j < 9)
304 break;
305 tty_print_char (' ');
306 if (current->submask & (1 << (j + topsublevel + 1)))
307 tty_print_char (ACS_VLINE);
308 else
309 tty_print_char (' ');
310 tty_print_char (' ');
312 tty_print_char (' '); j++;
313 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
314 tty_print_char (ACS_LLCORNER);
315 else
316 tty_print_char (ACS_LTEE);
317 tty_print_char (ACS_HLINE);
318 tty_set_alt_charset (FALSE);
320 if (tree->active && current == tree->selected_ptr) {
321 /* Selected directory -> change color */
322 if (!tty_use_colors () && !tree->is_panel)
323 tty_setcolor (MARKED_COLOR);
324 else
325 tty_setcolor (SELECTED_COLOR);
328 /* Show sub-name */
329 tty_print_char (' ');
330 tty_print_string (str_fit_to_term (current->subname,
331 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
333 tty_print_char (' ');
335 /* Return to normal color */
336 tty_setcolor (TREE_NORMALC (h));
338 /* Calculate the next value for current */
339 current = current->next;
340 if (tree_navigation_flag){
341 while (current){
342 if (current->sublevel < tree->selected_ptr->sublevel){
343 if (strncmp (current->name, tree->selected_ptr->name,
344 strlen (current->name)) == 0)
345 break;
346 } else if (current->sublevel == tree->selected_ptr->sublevel){
347 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
348 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
349 break;
350 } else if (current->sublevel == tree->selected_ptr->sublevel+1
351 && strlen (tree->selected_ptr->name) > 1){
352 if (strncmp (current->name, tree->selected_ptr->name,
353 strlen (tree->selected_ptr->name)) == 0)
354 break;
356 current = current->next;
360 tree_show_mini_info (tree, tree_lines, tree_cols);
363 static void
364 tree_check_focus (WTree *tree)
366 if (tree->topdiff < 3)
367 tree->topdiff = 3;
368 else if (tree->topdiff >= tlines (tree) - 3)
369 tree->topdiff = tlines (tree) - 3 - 1;
372 static void
373 tree_move_backward (WTree *tree, int i)
375 if (!tree_navigation_flag)
376 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
377 else {
378 tree_entry *current;
379 int j = 0;
381 current = tree->selected_ptr;
382 while (j < i && current->prev
383 && current->prev->sublevel >= tree->selected_ptr->sublevel){
384 current = current->prev;
385 if (current->sublevel == tree->selected_ptr->sublevel){
386 tree->selected_ptr = current;
387 j++;
390 i = j;
393 tree->topdiff -= i;
394 tree_check_focus (tree);
397 static void
398 tree_move_forward (WTree *tree, int i)
400 if (!tree_navigation_flag)
401 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
402 else {
403 tree_entry *current;
404 int j = 0;
406 current = tree->selected_ptr;
407 while (j < i && current->next
408 && current->next->sublevel >= tree->selected_ptr->sublevel){
409 current = current->next;
410 if (current->sublevel == tree->selected_ptr->sublevel){
411 tree->selected_ptr = current;
412 j ++;
415 i = j;
418 tree->topdiff += i;
419 tree_check_focus (tree);
422 static void
423 tree_move_to_child (WTree *tree)
425 tree_entry *current;
427 /* Do we have a starting point? */
428 if (!tree->selected_ptr)
429 return;
430 /* Take the next entry */
431 current = tree->selected_ptr->next;
432 /* Is it the child of the selected entry */
433 if (current && current->sublevel > tree->selected_ptr->sublevel){
434 /* Yes -> select this entry */
435 tree->selected_ptr = current;
436 tree->topdiff++;
437 tree_check_focus (tree);
438 } else {
439 /* No -> rescan and try again */
440 tree_rescan (tree);
441 current = tree->selected_ptr->next;
442 if (current && current->sublevel > tree->selected_ptr->sublevel){
443 tree->selected_ptr = current;
444 tree->topdiff++;
445 tree_check_focus (tree);
450 static gboolean
451 tree_move_to_parent (WTree *tree)
453 tree_entry *current;
454 tree_entry *old;
456 if (!tree->selected_ptr)
457 return FALSE;
459 old = tree->selected_ptr;
460 current = tree->selected_ptr->prev;
461 while (current && current->sublevel >= tree->selected_ptr->sublevel){
462 current = current->prev;
463 tree->topdiff--;
465 if (!current)
466 current = tree->store->tree_first;
467 tree->selected_ptr = current;
468 tree_check_focus (tree);
469 return tree->selected_ptr != old;
472 static void
473 tree_move_to_top (WTree *tree)
475 tree->selected_ptr = tree->store->tree_first;
476 tree->topdiff = 0;
479 static void
480 tree_move_to_bottom (WTree *tree)
482 tree->selected_ptr = tree->store->tree_last;
483 tree->topdiff = tlines (tree) - 3 - 1;
486 /* Handle mouse click */
487 static void
488 tree_event (WTree *tree, int y)
490 if (tree->tree_shown [y]){
491 tree->selected_ptr = tree->tree_shown [y];
492 tree->topdiff = y;
494 show_tree (tree);
497 static void
498 tree_chdir_sel (WTree *tree)
500 if (!tree->is_panel)
501 return;
503 change_panel ();
505 if (do_cd (tree->selected_ptr->name, cd_exact))
506 select_item (current_panel);
507 else
508 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
509 tree->selected_ptr->name, unix_error_string (errno));
511 change_panel ();
512 show_tree (tree);
515 static void
516 maybe_chdir (WTree *tree)
518 if (xtree_mode && tree->is_panel && is_idle ())
519 tree_chdir_sel (tree);
522 /* Mouse callback */
523 static int
524 event_callback (Gpm_Event *event, void *data)
526 WTree *tree = data;
528 /* rest of the upper frame, the menu is invisible - call menu */
529 if (tree->is_panel && (event->type & GPM_DOWN)
530 && event->y == 1 && !menubar_visible) {
531 event->x += tree->widget.x;
532 return the_menubar->widget.mouse (event, the_menubar);
535 if (!(event->type & GPM_UP))
536 return MOU_NORMAL;
538 if (tree->is_panel)
539 event->y--;
541 event->y--;
543 if (!tree->active)
544 change_panel ();
546 if (event->y < 0){
547 tree_move_backward (tree, tlines (tree) - 1);
548 show_tree (tree);
549 } else if (event->y >= tlines (tree)){
550 tree_move_forward (tree, tlines (tree) - 1);
551 show_tree (tree);
552 } else {
553 tree_event (tree, event->y);
554 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
555 tree_chdir_sel (tree);
558 return MOU_NORMAL;
561 /* Search tree for text */
562 static int
563 search_tree (WTree *tree, char *text)
565 tree_entry *current;
566 int len;
567 int wrapped = 0;
568 int found = 0;
570 len = strlen (text);
571 current = tree->selected_ptr;
572 found = 0;
573 while (!wrapped || current != tree->selected_ptr){
574 if (strncmp (current->subname, text, len) == 0){
575 tree->selected_ptr = current;
576 found = 1;
577 break;
579 current = current->next;
580 if (!current){
581 current = tree->store->tree_first;
582 wrapped = 1;
584 tree->topdiff++;
586 tree_check_focus (tree);
587 return found;
590 static void
591 tree_do_search (WTree *tree, int key)
593 size_t l;
595 l = strlen (tree->search_buffer);
596 if ((l != 0) && (key == KEY_BACKSPACE))
597 tree->search_buffer [--l] = '\0';
598 else if (key && l < sizeof (tree->search_buffer)){
599 tree->search_buffer [l] = key;
600 tree->search_buffer [++l] = '\0';
603 if (!search_tree (tree, tree->search_buffer))
604 tree->search_buffer [--l] = 0;
606 show_tree (tree);
607 maybe_chdir (tree);
610 static void
611 tree_rescan (void *data)
613 char old_dir [MC_MAXPATHLEN];
614 WTree *tree = data;
616 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
617 mc_chdir (tree->selected_ptr->name))
618 return;
620 tree_store_rescan (tree->selected_ptr->name);
621 mc_chdir (old_dir);
624 static void
625 tree_forget (void *data)
627 WTree *tree = data;
628 if (tree->selected_ptr)
629 tree_remove_entry (tree, tree->selected_ptr->name);
632 static void
633 tree_copy (WTree *tree, const char *default_dest)
635 char msg [BUF_MEDIUM];
636 char *dest;
637 off_t count = 0;
638 double bytes = 0;
639 FileOpContext *ctx;
641 if (tree->selected_ptr == NULL)
642 return;
644 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
645 str_trunc (tree->selected_ptr->name, 50));
646 dest = input_expand_dialog (Q_("DialogTitle|Copy"), msg, MC_HISTORY_FM_TREE_COPY, default_dest);
648 if (dest != NULL && *dest != '\0') {
649 ctx = file_op_context_new (OP_COPY);
650 file_op_context_create_ui (ctx, FALSE);
651 copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
652 file_op_context_destroy (ctx);
655 g_free (dest);
658 static void
659 tree_move (WTree *tree, const char *default_dest)
661 char msg [BUF_MEDIUM];
662 char *dest;
663 struct stat buf;
664 double bytes = 0;
665 off_t count = 0;
666 FileOpContext *ctx;
668 if (tree->selected_ptr == NULL)
669 return;
671 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
672 str_trunc (tree->selected_ptr->name, 50));
673 dest = input_expand_dialog (Q_("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
675 if (dest == NULL || *dest == '\0') {
676 g_free (dest);
677 return;
680 if (stat (dest, &buf)){
681 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
682 unix_error_string (errno));
683 g_free (dest);
684 return;
687 if (!S_ISDIR (buf.st_mode)){
688 file_error (_(" Destination \"%s\" must be a directory \n %s "),
689 dest);
690 g_free (dest);
691 return;
694 ctx = file_op_context_new (OP_MOVE);
695 file_op_context_create_ui (ctx, FALSE);
696 move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
697 file_op_context_destroy (ctx);
699 g_free (dest);
702 #if 0
703 static void
704 tree_mkdir (WTree *tree)
706 char old_dir [MC_MAXPATHLEN];
708 if (!tree->selected_ptr)
709 return;
710 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
711 return;
712 if (chdir (tree->selected_ptr->name))
713 return;
714 /* FIXME
715 mkdir_cmd (tree);
717 tree_rescan (tree);
718 chdir (old_dir);
720 #endif
722 static void
723 tree_rmdir (void *data)
725 WTree *tree = data;
726 off_t count = 0;
727 double bytes = 0;
728 FileOpContext *ctx;
730 if (!tree->selected_ptr)
731 return;
733 if (confirm_delete) {
734 char *buf;
735 int result;
737 buf =
738 g_strdup_printf (_(" Delete %s? "),
739 tree->selected_ptr->name);
740 result =
741 query_dialog (Q_("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
742 g_free (buf);
743 if (result != 0)
744 return;
747 ctx = file_op_context_new (OP_DELETE);
748 file_op_context_create_ui (ctx, FALSE);
749 if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
750 tree_forget (tree);
751 file_op_context_destroy (ctx);
754 static inline void
755 tree_move_up (WTree *tree)
757 tree_move_backward (tree, 1);
758 show_tree (tree);
759 maybe_chdir (tree);
762 static inline void
763 tree_move_down (WTree *tree)
765 tree_move_forward (tree, 1);
766 show_tree (tree);
767 maybe_chdir (tree);
770 static inline void
771 tree_move_home (WTree *tree)
773 tree_move_to_top (tree);
774 show_tree (tree);
775 maybe_chdir (tree);
778 static inline void
779 tree_move_end (WTree *tree)
781 tree_move_to_bottom (tree);
782 show_tree (tree);
783 maybe_chdir (tree);
786 static void
787 tree_move_pgup (WTree *tree)
789 tree_move_backward (tree, tlines (tree) - 1);
790 show_tree (tree);
791 maybe_chdir (tree);
794 static void
795 tree_move_pgdn (WTree *tree)
797 tree_move_forward (tree, tlines (tree) - 1);
798 show_tree (tree);
799 maybe_chdir (tree);
802 static gboolean
803 tree_move_left (WTree *tree)
805 gboolean v = FALSE;
807 if (tree_navigation_flag) {
808 v = tree_move_to_parent (tree);
809 show_tree (tree);
810 maybe_chdir (tree);
813 return v;
816 static gboolean
817 tree_move_right (WTree *tree)
819 gboolean v = FALSE;
821 if (tree_navigation_flag) {
822 tree_move_to_child (tree);
823 show_tree (tree);
824 maybe_chdir (tree);
825 v = TRUE;
828 return v;
831 static void
832 tree_start_search (WTree *tree)
834 gboolean i;
836 if (tree->searching) {
837 if (tree->selected_ptr == tree->store->tree_last)
838 tree_move_to_top (tree);
839 else {
840 /* set navigation mode temporarily to 'Static' because in
841 * dynamic navigation mode tree_move_forward will not move
842 * to a lower sublevel if necessary (sequent searches must
843 * start with the directory followed the last found directory)
845 i = tree_navigation_flag;
846 tree_navigation_flag = 0;
847 tree_move_forward (tree, 1);
848 tree_navigation_flag = i;
850 tree_do_search (tree, 0);
851 } else {
852 tree->searching = 1;
853 tree->search_buffer[0] = 0;
857 static void
858 tree_toggle_navig (WTree *tree)
860 tree_navigation_flag = !tree_navigation_flag;
861 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
862 tree_navigation_flag ? Q_("ButtonBar|Static")
863 : Q_("ButtonBar|Dynamc"),
864 tree_map, (Widget *) tree);
867 static cb_ret_t
868 tree_execute_cmd (WTree *tree, unsigned long command)
870 cb_ret_t res = MSG_HANDLED;
872 if (command != CK_TreeStartSearch)
873 tree->searching = 0;
875 switch (command) {
876 case CK_TreeHelp:
877 interactive_display (NULL, "[Directory Tree]");
878 break;
879 case CK_TreeForget:
880 tree_forget (tree);
881 break;
882 case CK_TreeToggleNav:
883 tree_toggle_navig (tree);
884 break;
885 case CK_TreeCopy:
886 tree_copy (tree, "");
887 break;
888 case CK_TreeMove:
889 tree_move (tree, "");
890 break;
891 case CK_TreeMoveUp:
892 tree_move_up (tree);
893 break;
894 case CK_TreeMoveDown:
895 tree_move_down (tree);
896 break;
897 case CK_TreeMoveHome:
898 tree_move_home (tree);
899 break;
900 case CK_TreeMoveEnd:
901 tree_move_end (tree);
902 break;
903 case CK_TreeMovePgUp:
904 tree_move_pgup (tree);
905 break;
906 case CK_TreeMovePgDn:
907 tree_move_pgdn (tree);
908 break;
909 case CK_TreeOpen:
910 tree_chdir_sel (tree);
911 break;
912 case CK_TreeRescan:
913 tree_rescan (tree);
914 break;
915 case CK_TreeStartSearch:
916 tree_start_search (tree);
917 break;
918 case CK_TreeRemove:
919 tree_rmdir (tree);
920 break;
921 default:
922 res = MSG_NOT_HANDLED;
925 show_tree (tree);
927 return res;
930 static cb_ret_t
931 tree_key (WTree *tree, int key)
933 size_t i;
935 for (i = 0; tree_map [i].key != 0; i++)
936 if (key == tree_map [i].key)
937 switch (tree_map [i].command) {
938 case CK_TreeMoveLeft:
939 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
940 case CK_TreeMoveRight:
941 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
942 default:
943 tree_execute_cmd (tree, tree_map [i].command);
944 return MSG_HANDLED;
947 if (is_abort_char (key)) {
948 if (tree->is_panel) {
949 tree->searching = 0;
950 show_tree (tree);
951 return MSG_HANDLED; /* eat abort char */
953 /* modal tree dialog: let upper layer see the
954 abort character and close the dialog */
955 return MSG_NOT_HANDLED;
958 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
959 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
960 if (tree->searching){
961 tree_do_search (tree, key);
962 show_tree (tree);
963 return MSG_HANDLED;
966 if (!command_prompt) {
967 tree_start_search (tree);
968 tree_do_search (tree, key);
969 return MSG_HANDLED;
971 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
974 return MSG_NOT_HANDLED;
977 static void
978 tree_frame (Dlg_head *h, WTree *tree)
980 tty_setcolor (NORMAL_COLOR);
981 widget_erase ((Widget*) tree);
982 if (tree->is_panel) {
983 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
984 tree->widget.cols);
986 if (show_mini_info)
987 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
988 tree->widget.x + 1,
989 ACS_HLINE, tree->widget.cols - 2);
993 static cb_ret_t
994 tree_callback (Widget *w, widget_msg_t msg, int parm)
996 WTree *tree = (WTree *) w;
997 Dlg_head *h = tree->widget.parent;
998 WButtonBar *b = find_buttonbar (h);
1000 switch (msg) {
1001 case WIDGET_DRAW:
1002 tree_frame (h, tree);
1003 show_tree (tree);
1004 return MSG_HANDLED;
1006 case WIDGET_FOCUS:
1007 tree->active = 1;
1008 buttonbar_set_label (b, 1, Q_("ButtonBar|Help"), tree_map, (Widget *) tree);
1009 buttonbar_set_label (b, 2, Q_("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1010 buttonbar_set_label (b, 3, Q_("ButtonBar|Forget"), tree_map, (Widget *) tree);
1011 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_("ButtonBar|Static")
1012 : Q_("ButtonBar|Dynamc"),
1013 tree_map, (Widget *) tree);
1014 buttonbar_set_label (b, 5, Q_("ButtonBar|Copy"), tree_map, (Widget *) tree);
1015 buttonbar_set_label (b, 6, Q_("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1016 #if 0
1017 /* FIXME: mkdir is currently defunct */
1018 buttonbar_set_label (b, 7, Q_("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1019 #else
1020 buttonbar_clear_label (b, 7, (Widget *) tree);
1021 #endif
1022 buttonbar_set_label (b, 8, Q_("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1023 buttonbar_redraw (b);
1025 /* FIXME: Should find a better way of only displaying the
1026 currently selected item */
1027 show_tree (tree);
1028 return MSG_HANDLED;
1030 /* FIXME: Should find a better way of changing the color of the
1031 selected item */
1033 case WIDGET_UNFOCUS:
1034 tree->active = 0;
1035 show_tree (tree);
1036 return MSG_HANDLED;
1038 case WIDGET_KEY:
1039 return tree_key (tree, parm);
1041 case WIDGET_COMMAND:
1042 /* command from buttonbar */
1043 return tree_execute_cmd (tree, parm);
1045 case WIDGET_DESTROY:
1046 tree_destroy (tree);
1047 return MSG_HANDLED;
1049 default:
1050 return default_proc (msg, parm);
1054 WTree *
1055 tree_new (int is_panel, int y, int x, int lines, int cols)
1057 WTree *tree = g_new (WTree, 1);
1059 init_widget (&tree->widget, y, x, lines, cols,
1060 tree_callback, event_callback);
1061 tree->is_panel = is_panel;
1062 tree->selected_ptr = 0;
1064 tree->store = tree_store_get ();
1065 tree_store_add_entry_remove_hook (remove_callback, tree);
1066 tree->tree_shown = 0;
1067 tree->search_buffer[0] = 0;
1068 tree->topdiff = tree->widget.lines / 2;
1069 tree->searching = 0;
1070 tree->active = 0;
1072 /* We do not want to keep the cursor */
1073 widget_want_cursor (tree->widget, 0);
1074 load_tree (tree);
1075 return tree;
1078 void
1079 tree_chdir (WTree *tree, const char *dir)
1081 tree_entry *current;
1083 current = tree_store_whereis (dir);
1085 if (current != NULL) {
1086 tree->selected_ptr = current;
1087 tree_check_focus (tree);
1091 /* Return name of the currently selected entry */
1092 char *
1093 tree_selected_name (const WTree *tree)
1095 return tree->selected_ptr->name;
1098 void
1099 sync_tree (const char *path)
1101 tree_chdir (the_tree, path);
1104 WTree *
1105 find_tree (struct Dlg_head *h)
1107 return (WTree *) find_widget_type (h, tree_callback);