Minor grammar/spelling issues.
[kaloumi3.git] / src / tree.c
blob30d0b0249c64918ad919e5f9d5e0473d0e78973d
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"
69 #include "filegui.h"
71 const global_keymap_t *tree_map;
73 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (show_mini_info ? 2 : 0) : t->widget.lines)
75 /* Use the color of the parent widget for the unselected entries */
76 #define TREE_NORMALC(h) (DLG_NORMALC (h))
78 /* Specifies the display mode: 1d or 2d */
79 static gboolean tree_navigation_flag = FALSE;
81 struct WTree
83 Widget widget;
84 struct TreeStore *store;
85 tree_entry *selected_ptr; /* The selected directory */
86 char search_buffer[256]; /* Current search string */
87 tree_entry **tree_shown; /* Entries currently on screen */
88 int is_panel; /* panel or plain widget flag */
89 int active; /* if it's currently selected */
90 int searching; /* Are we on searching mode? */
91 int topdiff; /* The difference between the topmost
92 shown and the selected */
95 /* Forwards */
96 static void tree_rescan (void *data);
98 static tree_entry *
99 back_ptr (tree_entry * ptr, int *count)
101 int i = 0;
103 while (ptr && ptr->prev && i < *count)
105 ptr = ptr->prev;
106 i++;
108 *count = i;
109 return ptr;
112 static tree_entry *
113 forw_ptr (tree_entry * ptr, int *count)
115 int i = 0;
117 while (ptr && ptr->next && i < *count)
119 ptr = ptr->next;
120 i++;
122 *count = i;
123 return ptr;
126 static void
127 remove_callback (tree_entry * entry, void *data)
129 WTree *tree = data;
131 if (tree->selected_ptr == entry)
133 if (tree->selected_ptr->next)
134 tree->selected_ptr = tree->selected_ptr->next;
135 else
136 tree->selected_ptr = tree->selected_ptr->prev;
140 /* Save the ~/.mc/Tree file */
141 static void
142 save_tree (WTree * tree)
144 int error;
145 char *tree_name;
147 (void) tree;
148 error = tree_store_save ();
151 if (error)
153 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR, MC_TREESTORE_FILE, (char *) NULL);
154 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
155 unix_error_string (error));
156 g_free (tree_name);
160 static void
161 tree_remove_entry (WTree * tree, char *name)
163 (void) tree;
164 tree_store_remove_entry (name);
167 static void
168 tree_destroy (WTree * tree)
170 tree_store_remove_entry_remove_hook (remove_callback);
171 save_tree (tree);
173 g_free (tree->tree_shown);
174 tree->tree_shown = 0;
175 tree->selected_ptr = NULL;
178 /* Loads the .mc.tree file */
179 static void
180 load_tree (WTree * tree)
182 tree_store_load ();
184 tree->selected_ptr = tree->store->tree_first;
185 tree_chdir (tree, home_dir);
188 static void
189 tree_show_mini_info (WTree * tree, int tree_lines, int tree_cols)
191 Dlg_head *h = tree->widget.parent;
192 int line;
194 /* Show mini info */
195 if (tree->is_panel)
197 if (!show_mini_info)
198 return;
199 line = tree_lines + 2;
201 else
202 line = tree_lines + 1;
204 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
205 widget_move (&tree->widget, line, 1);
207 if (tree->searching)
209 /* Show search string */
210 tty_setcolor (TREE_NORMALC (h));
211 tty_setcolor (DLG_FOCUSC (h));
212 tty_print_char (PATH_SEP);
214 tty_print_string (str_fit_to_term (tree->search_buffer, tree_cols - 2, J_LEFT_FIT));
215 tty_print_char (' ');
216 tty_setcolor (DLG_FOCUSC (h));
218 else
220 /* Show full name of selected directory */
221 tty_print_string (str_fit_to_term (tree->selected_ptr->name, tree_cols, J_LEFT_FIT));
225 static void
226 show_tree (WTree * tree)
228 Dlg_head *h = tree->widget.parent;
229 tree_entry *current;
230 int i, j, topsublevel;
231 int x, y;
232 int tree_lines, tree_cols;
234 /* Initialize */
235 x = y = 0;
236 tree_lines = tlines (tree);
237 tree_cols = tree->widget.cols;
239 tty_setcolor (TREE_NORMALC (h));
240 widget_move ((Widget *) tree, y, x);
241 if (tree->is_panel)
243 tree_cols -= 2;
244 x = y = 1;
247 g_free (tree->tree_shown);
248 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
250 if (tree->store->tree_first)
251 topsublevel = tree->store->tree_first->sublevel;
252 else
253 topsublevel = 0;
254 if (!tree->selected_ptr)
256 tree->selected_ptr = tree->store->tree_first;
257 tree->topdiff = 0;
259 current = tree->selected_ptr;
261 /* Calculate the directory which is to be shown on the topmost line */
262 if (!tree_navigation_flag)
263 current = back_ptr (current, &tree->topdiff);
264 else
266 i = 0;
267 while (current->prev && i < tree->topdiff)
269 current = current->prev;
270 if (current->sublevel < tree->selected_ptr->sublevel)
272 if (strncmp (current->name, tree->selected_ptr->name, strlen (current->name)) == 0)
273 i++;
275 else if (current->sublevel == tree->selected_ptr->sublevel)
277 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--);
278 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
279 i++;
281 else if (current->sublevel == tree->selected_ptr->sublevel + 1
282 && strlen (tree->selected_ptr->name) > 1)
284 if (strncmp (current->name, tree->selected_ptr->name,
285 strlen (tree->selected_ptr->name)) == 0)
286 i++;
289 tree->topdiff = i;
292 /* Loop for every line */
293 for (i = 0; i < tree_lines; i++)
295 /* Move to the beginning of the line */
296 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x, ' ', tree_cols);
298 if (!current)
299 continue;
301 tree->tree_shown[i] = current;
302 if (current->sublevel == topsublevel)
305 /* Top level directory */
306 if (tree->active && current == tree->selected_ptr)
308 if (!tty_use_colors () && !tree->is_panel)
309 tty_setcolor (MARKED_COLOR);
310 else
311 tty_setcolor (SELECTED_COLOR);
314 /* Show full name */
315 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
317 else
319 /* Sub level directory */
321 tty_set_alt_charset (TRUE);
322 /* Output branch parts */
323 for (j = 0; j < current->sublevel - topsublevel - 1; j++)
325 if (tree_cols - 8 - 3 * j < 9)
326 break;
327 tty_print_char (' ');
328 if (current->submask & (1 << (j + topsublevel + 1)))
329 tty_print_char (ACS_VLINE);
330 else
331 tty_print_char (' ');
332 tty_print_char (' ');
334 tty_print_char (' ');
335 j++;
336 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
337 tty_print_char (ACS_LLCORNER);
338 else
339 tty_print_char (ACS_LTEE);
340 tty_print_char (ACS_HLINE);
341 tty_set_alt_charset (FALSE);
343 if (tree->active && current == tree->selected_ptr)
345 /* Selected directory -> change color */
346 if (!tty_use_colors () && !tree->is_panel)
347 tty_setcolor (MARKED_COLOR);
348 else
349 tty_setcolor (SELECTED_COLOR);
352 /* Show sub-name */
353 tty_print_char (' ');
354 tty_print_string (str_fit_to_term (current->subname,
355 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
357 tty_print_char (' ');
359 /* Return to normal color */
360 tty_setcolor (TREE_NORMALC (h));
362 /* Calculate the next value for current */
363 current = current->next;
364 if (tree_navigation_flag)
366 while (current)
368 if (current->sublevel < tree->selected_ptr->sublevel)
370 if (strncmp (current->name, tree->selected_ptr->name,
371 strlen (current->name)) == 0)
372 break;
374 else if (current->sublevel == tree->selected_ptr->sublevel)
376 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--);
377 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
378 break;
380 else if (current->sublevel == tree->selected_ptr->sublevel + 1
381 && strlen (tree->selected_ptr->name) > 1)
383 if (strncmp (current->name, tree->selected_ptr->name,
384 strlen (tree->selected_ptr->name)) == 0)
385 break;
387 current = current->next;
391 tree_show_mini_info (tree, tree_lines, tree_cols);
394 static void
395 tree_check_focus (WTree * tree)
397 if (tree->topdiff < 3)
398 tree->topdiff = 3;
399 else if (tree->topdiff >= tlines (tree) - 3)
400 tree->topdiff = tlines (tree) - 3 - 1;
403 static void
404 tree_move_backward (WTree * tree, int i)
406 if (!tree_navigation_flag)
407 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
408 else
410 tree_entry *current;
411 int j = 0;
413 current = tree->selected_ptr;
414 while (j < i && current->prev && current->prev->sublevel >= tree->selected_ptr->sublevel)
416 current = current->prev;
417 if (current->sublevel == tree->selected_ptr->sublevel)
419 tree->selected_ptr = current;
420 j++;
423 i = j;
426 tree->topdiff -= i;
427 tree_check_focus (tree);
430 static void
431 tree_move_forward (WTree * tree, int i)
433 if (!tree_navigation_flag)
434 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
435 else
437 tree_entry *current;
438 int j = 0;
440 current = tree->selected_ptr;
441 while (j < i && current->next && current->next->sublevel >= tree->selected_ptr->sublevel)
443 current = current->next;
444 if (current->sublevel == tree->selected_ptr->sublevel)
446 tree->selected_ptr = current;
447 j++;
450 i = j;
453 tree->topdiff += i;
454 tree_check_focus (tree);
457 static void
458 tree_move_to_child (WTree * tree)
460 tree_entry *current;
462 /* Do we have a starting point? */
463 if (!tree->selected_ptr)
464 return;
465 /* Take the next entry */
466 current = tree->selected_ptr->next;
467 /* Is it the child of the selected entry */
468 if (current && current->sublevel > tree->selected_ptr->sublevel)
470 /* Yes -> select this entry */
471 tree->selected_ptr = current;
472 tree->topdiff++;
473 tree_check_focus (tree);
475 else
477 /* No -> rescan and try again */
478 tree_rescan (tree);
479 current = tree->selected_ptr->next;
480 if (current && current->sublevel > tree->selected_ptr->sublevel)
482 tree->selected_ptr = current;
483 tree->topdiff++;
484 tree_check_focus (tree);
489 static gboolean
490 tree_move_to_parent (WTree * tree)
492 tree_entry *current;
493 tree_entry *old;
495 if (!tree->selected_ptr)
496 return FALSE;
498 old = tree->selected_ptr;
499 current = tree->selected_ptr->prev;
500 while (current && current->sublevel >= tree->selected_ptr->sublevel)
502 current = current->prev;
503 tree->topdiff--;
505 if (!current)
506 current = tree->store->tree_first;
507 tree->selected_ptr = current;
508 tree_check_focus (tree);
509 return tree->selected_ptr != old;
512 static void
513 tree_move_to_top (WTree * tree)
515 tree->selected_ptr = tree->store->tree_first;
516 tree->topdiff = 0;
519 static void
520 tree_move_to_bottom (WTree * tree)
522 tree->selected_ptr = tree->store->tree_last;
523 tree->topdiff = tlines (tree) - 3 - 1;
526 /* Handle mouse click */
527 static void
528 tree_event (WTree * tree, int y)
530 if (tree->tree_shown[y])
532 tree->selected_ptr = tree->tree_shown[y];
533 tree->topdiff = y;
535 show_tree (tree);
538 static void
539 tree_chdir_sel (WTree * tree)
541 if (!tree->is_panel)
542 return;
544 change_panel ();
546 if (do_cd (tree->selected_ptr->name, cd_exact))
547 select_item (current_panel);
548 else
549 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
550 tree->selected_ptr->name, unix_error_string (errno));
552 change_panel ();
553 show_tree (tree);
556 static void
557 maybe_chdir (WTree * tree)
559 if (xtree_mode && tree->is_panel && is_idle ())
560 tree_chdir_sel (tree);
563 /* Mouse callback */
564 static int
565 event_callback (Gpm_Event * event, void *data)
567 WTree *tree = data;
569 /* rest of the upper frame, the menu is invisible - call menu */
570 if (tree->is_panel && (event->type & GPM_DOWN) && event->y == 1 && !menubar_visible)
572 event->x += tree->widget.x;
573 return the_menubar->widget.mouse (event, the_menubar);
576 if (!(event->type & GPM_UP))
577 return MOU_NORMAL;
579 if (tree->is_panel)
580 event->y--;
582 event->y--;
584 if (!tree->active)
585 change_panel ();
587 if (event->y < 0)
589 tree_move_backward (tree, tlines (tree) - 1);
590 show_tree (tree);
592 else if (event->y >= tlines (tree))
594 tree_move_forward (tree, tlines (tree) - 1);
595 show_tree (tree);
597 else
599 tree_event (tree, event->y);
600 if ((event->type & (GPM_UP | GPM_DOUBLE)) == (GPM_UP | GPM_DOUBLE))
602 tree_chdir_sel (tree);
605 return MOU_NORMAL;
608 /* Search tree for text */
609 static int
610 search_tree (WTree * tree, char *text)
612 tree_entry *current;
613 int len;
614 int wrapped = 0;
615 int found = 0;
617 len = strlen (text);
618 current = tree->selected_ptr;
619 found = 0;
620 while (!wrapped || current != tree->selected_ptr)
622 if (strncmp (current->subname, text, len) == 0)
624 tree->selected_ptr = current;
625 found = 1;
626 break;
628 current = current->next;
629 if (!current)
631 current = tree->store->tree_first;
632 wrapped = 1;
634 tree->topdiff++;
636 tree_check_focus (tree);
637 return found;
640 static void
641 tree_do_search (WTree * tree, int key)
643 size_t l;
645 l = strlen (tree->search_buffer);
646 if ((l != 0) && (key == KEY_BACKSPACE))
647 tree->search_buffer[--l] = '\0';
648 else if (key && l < sizeof (tree->search_buffer))
650 tree->search_buffer[l] = key;
651 tree->search_buffer[++l] = '\0';
654 if (!search_tree (tree, tree->search_buffer))
655 tree->search_buffer[--l] = 0;
657 show_tree (tree);
658 maybe_chdir (tree);
661 static void
662 tree_rescan (void *data)
664 char old_dir[MC_MAXPATHLEN];
665 WTree *tree = data;
667 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
668 mc_chdir (tree->selected_ptr->name))
669 return;
671 tree_store_rescan (tree->selected_ptr->name);
672 mc_chdir (old_dir);
675 static void
676 tree_forget (void *data)
678 WTree *tree = data;
679 if (tree->selected_ptr)
680 tree_remove_entry (tree, tree->selected_ptr->name);
683 static void
684 tree_copy (WTree * tree, const char *default_dest)
686 char msg[BUF_MEDIUM];
687 char *dest;
689 if (tree->selected_ptr == NULL)
690 return;
692 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
693 str_trunc (tree->selected_ptr->name, 50));
694 dest = input_expand_dialog (Q_ ("DialogTitle|Copy"),
695 msg, MC_HISTORY_FM_TREE_COPY, default_dest);
697 if (dest != NULL && *dest != '\0')
699 FileOpContext *ctx;
700 FileOpTotalContext *tctx;
702 ctx = file_op_context_new (OP_COPY);
703 tctx = file_op_total_context_new ();
704 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_MULTI_ITEM);
705 tctx->ask_overwrite = FALSE;
706 tctx->is_toplevel_file = FALSE;
707 copy_dir_dir (tctx, ctx, tree->selected_ptr->name, dest, TRUE, FALSE, FALSE, NULL);
708 file_op_total_context_destroy (tctx);
709 file_op_context_destroy (ctx);
712 g_free (dest);
715 static void
716 tree_move (WTree * tree, const char *default_dest)
718 char msg[BUF_MEDIUM];
719 char *dest;
720 struct stat buf;
721 FileOpContext *ctx;
722 FileOpTotalContext *tctx;
724 if (tree->selected_ptr == NULL)
725 return;
727 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
728 str_trunc (tree->selected_ptr->name, 50));
729 dest =
730 input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
732 if (dest == NULL || *dest == '\0')
734 g_free (dest);
735 return;
738 if (stat (dest, &buf))
740 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
741 unix_error_string (errno));
742 g_free (dest);
743 return;
746 if (!S_ISDIR (buf.st_mode))
748 file_error (_(" Destination \"%s\" must be a directory \n %s "), dest);
749 g_free (dest);
750 return;
753 ctx = file_op_context_new (OP_MOVE);
754 tctx = file_op_total_context_new ();
755 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
756 move_dir_dir (tctx, ctx, tree->selected_ptr->name, dest);
757 file_op_total_context_destroy (tctx);
758 file_op_context_destroy (ctx);
760 g_free (dest);
763 #if 0
764 static void
765 tree_mkdir (WTree * tree)
767 char old_dir[MC_MAXPATHLEN];
769 if (!tree->selected_ptr)
770 return;
771 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
772 return;
773 if (chdir (tree->selected_ptr->name))
774 return;
775 /* FIXME
776 mkdir_cmd (tree);
778 tree_rescan (tree);
779 chdir (old_dir);
781 #endif
783 static void
784 tree_rmdir (void *data)
786 WTree *tree = data;
787 FileOpContext *ctx;
788 FileOpTotalContext *tctx;
790 if (!tree->selected_ptr)
791 return;
793 if (confirm_delete)
795 char *buf;
796 int result;
798 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
799 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
800 g_free (buf);
801 if (result != 0)
802 return;
805 ctx = file_op_context_new (OP_DELETE);
806 tctx = file_op_total_context_new ();
808 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
809 if (erase_dir (tctx, ctx, tree->selected_ptr->name) == FILE_CONT)
810 tree_forget (tree);
811 file_op_total_context_destroy (tctx);
812 file_op_context_destroy (ctx);
815 static inline void
816 tree_move_up (WTree * tree)
818 tree_move_backward (tree, 1);
819 show_tree (tree);
820 maybe_chdir (tree);
823 static inline void
824 tree_move_down (WTree * tree)
826 tree_move_forward (tree, 1);
827 show_tree (tree);
828 maybe_chdir (tree);
831 static inline void
832 tree_move_home (WTree * tree)
834 tree_move_to_top (tree);
835 show_tree (tree);
836 maybe_chdir (tree);
839 static inline void
840 tree_move_end (WTree * tree)
842 tree_move_to_bottom (tree);
843 show_tree (tree);
844 maybe_chdir (tree);
847 static void
848 tree_move_pgup (WTree * tree)
850 tree_move_backward (tree, tlines (tree) - 1);
851 show_tree (tree);
852 maybe_chdir (tree);
855 static void
856 tree_move_pgdn (WTree * tree)
858 tree_move_forward (tree, tlines (tree) - 1);
859 show_tree (tree);
860 maybe_chdir (tree);
863 static gboolean
864 tree_move_left (WTree * tree)
866 gboolean v = FALSE;
868 if (tree_navigation_flag)
870 v = tree_move_to_parent (tree);
871 show_tree (tree);
872 maybe_chdir (tree);
875 return v;
878 static gboolean
879 tree_move_right (WTree * tree)
881 gboolean v = FALSE;
883 if (tree_navigation_flag)
885 tree_move_to_child (tree);
886 show_tree (tree);
887 maybe_chdir (tree);
888 v = TRUE;
891 return v;
894 static void
895 tree_start_search (WTree * tree)
897 gboolean i;
899 if (tree->searching)
901 if (tree->selected_ptr == tree->store->tree_last)
902 tree_move_to_top (tree);
903 else
905 /* set navigation mode temporarily to 'Static' because in
906 * dynamic navigation mode tree_move_forward will not move
907 * to a lower sublevel if necessary (sequent searches must
908 * start with the directory followed the last found directory)
910 i = tree_navigation_flag;
911 tree_navigation_flag = 0;
912 tree_move_forward (tree, 1);
913 tree_navigation_flag = i;
915 tree_do_search (tree, 0);
917 else
919 tree->searching = 1;
920 tree->search_buffer[0] = 0;
924 static void
925 tree_toggle_navig (WTree * tree)
927 tree_navigation_flag = !tree_navigation_flag;
928 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
929 tree_navigation_flag ? Q_ ("ButtonBar|Static")
930 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
933 static cb_ret_t
934 tree_execute_cmd (WTree * tree, unsigned long command)
936 cb_ret_t res = MSG_HANDLED;
938 if (command != CK_TreeStartSearch)
939 tree->searching = 0;
941 switch (command)
943 case CK_TreeHelp:
944 interactive_display (NULL, "[Directory Tree]");
945 break;
946 case CK_TreeForget:
947 tree_forget (tree);
948 break;
949 case CK_TreeToggleNav:
950 tree_toggle_navig (tree);
951 break;
952 case CK_TreeCopy:
953 tree_copy (tree, "");
954 break;
955 case CK_TreeMove:
956 tree_move (tree, "");
957 break;
958 case CK_TreeMoveUp:
959 tree_move_up (tree);
960 break;
961 case CK_TreeMoveDown:
962 tree_move_down (tree);
963 break;
964 case CK_TreeMoveHome:
965 tree_move_home (tree);
966 break;
967 case CK_TreeMoveEnd:
968 tree_move_end (tree);
969 break;
970 case CK_TreeMovePgUp:
971 tree_move_pgup (tree);
972 break;
973 case CK_TreeMovePgDn:
974 tree_move_pgdn (tree);
975 break;
976 case CK_TreeOpen:
977 tree_chdir_sel (tree);
978 break;
979 case CK_TreeRescan:
980 tree_rescan (tree);
981 break;
982 case CK_TreeStartSearch:
983 tree_start_search (tree);
984 break;
985 case CK_TreeRemove:
986 tree_rmdir (tree);
987 break;
988 default:
989 res = MSG_NOT_HANDLED;
992 show_tree (tree);
994 return res;
997 static cb_ret_t
998 tree_key (WTree * tree, int key)
1000 size_t i;
1002 for (i = 0; tree_map[i].key != 0; i++)
1003 if (key == tree_map[i].key)
1004 switch (tree_map[i].command)
1006 case CK_TreeMoveLeft:
1007 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1008 case CK_TreeMoveRight:
1009 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1010 default:
1011 tree_execute_cmd (tree, tree_map[i].command);
1012 return MSG_HANDLED;
1015 if (is_abort_char (key))
1017 if (tree->is_panel)
1019 tree->searching = 0;
1020 show_tree (tree);
1021 return MSG_HANDLED; /* eat abort char */
1023 /* modal tree dialog: let upper layer see the
1024 abort character and close the dialog */
1025 return MSG_NOT_HANDLED;
1028 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1029 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE)
1031 if (tree->searching)
1033 tree_do_search (tree, key);
1034 show_tree (tree);
1035 return MSG_HANDLED;
1038 if (!command_prompt)
1040 tree_start_search (tree);
1041 tree_do_search (tree, key);
1042 return MSG_HANDLED;
1044 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
1047 return MSG_NOT_HANDLED;
1050 static void
1051 tree_frame (Dlg_head * h, WTree * tree)
1053 tty_setcolor (NORMAL_COLOR);
1054 widget_erase ((Widget *) tree);
1055 if (tree->is_panel)
1057 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines, tree->widget.cols, FALSE);
1059 if (show_mini_info)
1060 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
1061 tree->widget.x + 1, ACS_HLINE, tree->widget.cols - 2);
1065 static cb_ret_t
1066 tree_callback (Widget * w, widget_msg_t msg, int parm)
1068 WTree *tree = (WTree *) w;
1069 Dlg_head *h = tree->widget.parent;
1070 WButtonBar *b = find_buttonbar (h);
1072 switch (msg)
1074 case WIDGET_DRAW:
1075 tree_frame (h, tree);
1076 show_tree (tree);
1077 return MSG_HANDLED;
1079 case WIDGET_FOCUS:
1080 tree->active = 1;
1081 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), tree_map, (Widget *) tree);
1082 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1083 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Forget"), tree_map, (Widget *) tree);
1084 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_ ("ButtonBar|Static")
1085 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
1086 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), tree_map, (Widget *) tree);
1087 buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1088 #if 0
1089 /* FIXME: mkdir is currently defunct */
1090 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1091 #else
1092 buttonbar_clear_label (b, 7, (Widget *) tree);
1093 #endif
1094 buttonbar_set_label (b, 8, Q_ ("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1095 buttonbar_redraw (b);
1097 /* FIXME: Should find a better way of only displaying the
1098 currently selected item */
1099 show_tree (tree);
1100 return MSG_HANDLED;
1102 /* FIXME: Should find a better way of changing the color of the
1103 selected item */
1105 case WIDGET_UNFOCUS:
1106 tree->active = 0;
1107 show_tree (tree);
1108 return MSG_HANDLED;
1110 case WIDGET_KEY:
1111 return tree_key (tree, parm);
1113 case WIDGET_COMMAND:
1114 /* command from buttonbar */
1115 return tree_execute_cmd (tree, parm);
1117 case WIDGET_DESTROY:
1118 tree_destroy (tree);
1119 return MSG_HANDLED;
1121 default:
1122 return default_proc (msg, parm);
1126 WTree *
1127 tree_new (int is_panel, int y, int x, int lines, int cols)
1129 WTree *tree = g_new (WTree, 1);
1131 init_widget (&tree->widget, y, x, lines, cols, tree_callback, event_callback);
1132 tree->is_panel = is_panel;
1133 tree->selected_ptr = 0;
1135 tree->store = tree_store_get ();
1136 tree_store_add_entry_remove_hook (remove_callback, tree);
1137 tree->tree_shown = 0;
1138 tree->search_buffer[0] = 0;
1139 tree->topdiff = tree->widget.lines / 2;
1140 tree->searching = 0;
1141 tree->active = 0;
1143 /* We do not want to keep the cursor */
1144 widget_want_cursor (tree->widget, 0);
1145 load_tree (tree);
1146 return tree;
1149 void
1150 tree_chdir (WTree * tree, const char *dir)
1152 tree_entry *current;
1154 current = tree_store_whereis (dir);
1156 if (current != NULL)
1158 tree->selected_ptr = current;
1159 tree_check_focus (tree);
1163 /* Return name of the currently selected entry */
1164 char *
1165 tree_selected_name (const WTree * tree)
1167 return tree->selected_ptr->name;
1170 void
1171 sync_tree (const char *path)
1173 tree_chdir (the_tree, path);
1176 WTree *
1177 find_tree (struct Dlg_head *h)
1179 return (WTree *) find_widget_type (h, tree_callback);