Removed hardcoded hotkeys in dialog.c Replaced keymap's initialization from main...
[pantumic.git] / src / tree.c
blob8dacd48ec2da8f37758f5d3416c70fb65c94affd
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 #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
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)
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)
117 ptr = ptr->next;
118 i++;
120 *count = i;
121 return ptr;
124 static void
125 remove_callback (tree_entry * entry, void *data)
127 WTree *tree = data;
129 if (tree->selected_ptr == entry)
131 if (tree->selected_ptr->next)
132 tree->selected_ptr = tree->selected_ptr->next;
133 else
134 tree->selected_ptr = tree->selected_ptr->prev;
138 /* Save the ~/.mc/Tree file */
139 static void
140 save_tree (WTree * tree)
142 int error;
143 char *tree_name;
145 (void) tree;
146 error = tree_store_save ();
149 if (error)
151 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR, MC_TREESTORE_FILE, (char *) NULL);
152 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
153 unix_error_string (error));
154 g_free (tree_name);
158 static void
159 tree_remove_entry (WTree * tree, char *name)
161 (void) tree;
162 tree_store_remove_entry (name);
165 static void
166 tree_destroy (WTree * tree)
168 tree_store_remove_entry_remove_hook (remove_callback);
169 save_tree (tree);
171 g_free (tree->tree_shown);
172 tree->tree_shown = 0;
173 tree->selected_ptr = NULL;
176 /* Loads the .mc.tree file */
177 static void
178 load_tree (WTree * tree)
180 tree_store_load ();
182 tree->selected_ptr = tree->store->tree_first;
183 tree_chdir (tree, home_dir);
186 static void
187 tree_show_mini_info (WTree * tree, int tree_lines, int tree_cols)
189 Dlg_head *h = tree->widget.parent;
190 int line;
192 /* Show mini info */
193 if (tree->is_panel)
195 if (!show_mini_info)
196 return;
197 line = tree_lines + 2;
199 else
200 line = tree_lines + 1;
202 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
203 widget_move (&tree->widget, line, 1);
205 if (tree->searching)
207 /* Show search string */
208 tty_setcolor (TREE_NORMALC (h));
209 tty_setcolor (DLG_FOCUSC (h));
210 tty_print_char (PATH_SEP);
212 tty_print_string (str_fit_to_term (tree->search_buffer, tree_cols - 2, J_LEFT_FIT));
213 tty_print_char (' ');
214 tty_setcolor (DLG_FOCUSC (h));
216 else
218 /* Show full name of selected directory */
219 tty_print_string (str_fit_to_term (tree->selected_ptr->name, tree_cols, J_LEFT_FIT));
223 static void
224 show_tree (WTree * tree)
226 Dlg_head *h = tree->widget.parent;
227 tree_entry *current;
228 int i, j, topsublevel;
229 int x, y;
230 int tree_lines, tree_cols;
232 /* Initialize */
233 x = y = 0;
234 tree_lines = tlines (tree);
235 tree_cols = tree->widget.cols;
237 tty_setcolor (TREE_NORMALC (h));
238 widget_move ((Widget *) tree, y, x);
239 if (tree->is_panel)
241 tree_cols -= 2;
242 x = y = 1;
245 g_free (tree->tree_shown);
246 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
248 if (tree->store->tree_first)
249 topsublevel = tree->store->tree_first->sublevel;
250 else
251 topsublevel = 0;
252 if (!tree->selected_ptr)
254 tree->selected_ptr = tree->store->tree_first;
255 tree->topdiff = 0;
257 current = tree->selected_ptr;
259 /* Calculate the directory which is to be shown on the topmost line */
260 if (!tree_navigation_flag)
261 current = back_ptr (current, &tree->topdiff);
262 else
264 i = 0;
265 while (current->prev && i < tree->topdiff)
267 current = current->prev;
268 if (current->sublevel < tree->selected_ptr->sublevel)
270 if (strncmp (current->name, tree->selected_ptr->name, strlen (current->name)) == 0)
271 i++;
273 else if (current->sublevel == tree->selected_ptr->sublevel)
275 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--);
276 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
277 i++;
279 else if (current->sublevel == tree->selected_ptr->sublevel + 1
280 && strlen (tree->selected_ptr->name) > 1)
282 if (strncmp (current->name, tree->selected_ptr->name,
283 strlen (tree->selected_ptr->name)) == 0)
284 i++;
287 tree->topdiff = i;
290 /* Loop for every line */
291 for (i = 0; i < tree_lines; i++)
293 /* Move to the beginning of the line */
294 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x, ' ', tree_cols);
296 if (!current)
297 continue;
299 tree->tree_shown[i] = current;
300 if (current->sublevel == topsublevel)
303 /* Top level directory */
304 if (tree->active && current == tree->selected_ptr)
306 if (!tty_use_colors () && !tree->is_panel)
307 tty_setcolor (MARKED_COLOR);
308 else
309 tty_setcolor (SELECTED_COLOR);
312 /* Show full name */
313 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
315 else
317 /* Sub level directory */
319 tty_set_alt_charset (TRUE);
320 /* Output branch parts */
321 for (j = 0; j < current->sublevel - topsublevel - 1; j++)
323 if (tree_cols - 8 - 3 * j < 9)
324 break;
325 tty_print_char (' ');
326 if (current->submask & (1 << (j + topsublevel + 1)))
327 tty_print_char (ACS_VLINE);
328 else
329 tty_print_char (' ');
330 tty_print_char (' ');
332 tty_print_char (' ');
333 j++;
334 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
335 tty_print_char (ACS_LLCORNER);
336 else
337 tty_print_char (ACS_LTEE);
338 tty_print_char (ACS_HLINE);
339 tty_set_alt_charset (FALSE);
341 if (tree->active && current == tree->selected_ptr)
343 /* Selected directory -> change color */
344 if (!tty_use_colors () && !tree->is_panel)
345 tty_setcolor (MARKED_COLOR);
346 else
347 tty_setcolor (SELECTED_COLOR);
350 /* Show sub-name */
351 tty_print_char (' ');
352 tty_print_string (str_fit_to_term (current->subname,
353 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
355 tty_print_char (' ');
357 /* Return to normal color */
358 tty_setcolor (TREE_NORMALC (h));
360 /* Calculate the next value for current */
361 current = current->next;
362 if (tree_navigation_flag)
364 while (current)
366 if (current->sublevel < tree->selected_ptr->sublevel)
368 if (strncmp (current->name, tree->selected_ptr->name,
369 strlen (current->name)) == 0)
370 break;
372 else if (current->sublevel == tree->selected_ptr->sublevel)
374 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--);
375 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
376 break;
378 else if (current->sublevel == tree->selected_ptr->sublevel + 1
379 && strlen (tree->selected_ptr->name) > 1)
381 if (strncmp (current->name, tree->selected_ptr->name,
382 strlen (tree->selected_ptr->name)) == 0)
383 break;
385 current = current->next;
389 tree_show_mini_info (tree, tree_lines, tree_cols);
392 static void
393 tree_check_focus (WTree * tree)
395 if (tree->topdiff < 3)
396 tree->topdiff = 3;
397 else if (tree->topdiff >= tlines (tree) - 3)
398 tree->topdiff = tlines (tree) - 3 - 1;
401 static void
402 tree_move_backward (WTree * tree, int i)
404 if (!tree_navigation_flag)
405 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
406 else
408 tree_entry *current;
409 int j = 0;
411 current = tree->selected_ptr;
412 while (j < i && current->prev && current->prev->sublevel >= tree->selected_ptr->sublevel)
414 current = current->prev;
415 if (current->sublevel == tree->selected_ptr->sublevel)
417 tree->selected_ptr = current;
418 j++;
421 i = j;
424 tree->topdiff -= i;
425 tree_check_focus (tree);
428 static void
429 tree_move_forward (WTree * tree, int i)
431 if (!tree_navigation_flag)
432 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
433 else
435 tree_entry *current;
436 int j = 0;
438 current = tree->selected_ptr;
439 while (j < i && current->next && current->next->sublevel >= tree->selected_ptr->sublevel)
441 current = current->next;
442 if (current->sublevel == tree->selected_ptr->sublevel)
444 tree->selected_ptr = current;
445 j++;
448 i = j;
451 tree->topdiff += i;
452 tree_check_focus (tree);
455 static void
456 tree_move_to_child (WTree * tree)
458 tree_entry *current;
460 /* Do we have a starting point? */
461 if (!tree->selected_ptr)
462 return;
463 /* Take the next entry */
464 current = tree->selected_ptr->next;
465 /* Is it the child of the selected entry */
466 if (current && current->sublevel > tree->selected_ptr->sublevel)
468 /* Yes -> select this entry */
469 tree->selected_ptr = current;
470 tree->topdiff++;
471 tree_check_focus (tree);
473 else
475 /* No -> rescan and try again */
476 tree_rescan (tree);
477 current = tree->selected_ptr->next;
478 if (current && current->sublevel > tree->selected_ptr->sublevel)
480 tree->selected_ptr = current;
481 tree->topdiff++;
482 tree_check_focus (tree);
487 static gboolean
488 tree_move_to_parent (WTree * tree)
490 tree_entry *current;
491 tree_entry *old;
493 if (!tree->selected_ptr)
494 return FALSE;
496 old = tree->selected_ptr;
497 current = tree->selected_ptr->prev;
498 while (current && current->sublevel >= tree->selected_ptr->sublevel)
500 current = current->prev;
501 tree->topdiff--;
503 if (!current)
504 current = tree->store->tree_first;
505 tree->selected_ptr = current;
506 tree_check_focus (tree);
507 return tree->selected_ptr != old;
510 static void
511 tree_move_to_top (WTree * tree)
513 tree->selected_ptr = tree->store->tree_first;
514 tree->topdiff = 0;
517 static void
518 tree_move_to_bottom (WTree * tree)
520 tree->selected_ptr = tree->store->tree_last;
521 tree->topdiff = tlines (tree) - 3 - 1;
524 /* Handle mouse click */
525 static void
526 tree_event (WTree * tree, int y)
528 if (tree->tree_shown[y])
530 tree->selected_ptr = tree->tree_shown[y];
531 tree->topdiff = y;
533 show_tree (tree);
536 static void
537 tree_chdir_sel (WTree * tree)
539 if (!tree->is_panel)
540 return;
542 change_panel ();
544 if (do_cd (tree->selected_ptr->name, cd_exact))
545 select_item (current_panel);
546 else
547 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
548 tree->selected_ptr->name, unix_error_string (errno));
550 change_panel ();
551 show_tree (tree);
554 static void
555 maybe_chdir (WTree * tree)
557 if (xtree_mode && tree->is_panel && is_idle ())
558 tree_chdir_sel (tree);
561 /* Mouse callback */
562 static int
563 event_callback (Gpm_Event * event, void *data)
565 WTree *tree = data;
567 /* rest of the upper frame, the menu is invisible - call menu */
568 if (tree->is_panel && (event->type & GPM_DOWN) && event->y == 1 && !menubar_visible)
570 event->x += tree->widget.x;
571 return the_menubar->widget.mouse (event, the_menubar);
574 if (!(event->type & GPM_UP))
575 return MOU_NORMAL;
577 if (tree->is_panel)
578 event->y--;
580 event->y--;
582 if (!tree->active)
583 change_panel ();
585 if (event->y < 0)
587 tree_move_backward (tree, tlines (tree) - 1);
588 show_tree (tree);
590 else if (event->y >= tlines (tree))
592 tree_move_forward (tree, tlines (tree) - 1);
593 show_tree (tree);
595 else
597 tree_event (tree, event->y);
598 if ((event->type & (GPM_UP | GPM_DOUBLE)) == (GPM_UP | GPM_DOUBLE))
600 tree_chdir_sel (tree);
603 return MOU_NORMAL;
606 /* Search tree for text */
607 static int
608 search_tree (WTree * tree, char *text)
610 tree_entry *current;
611 int len;
612 int wrapped = 0;
613 int found = 0;
615 len = strlen (text);
616 current = tree->selected_ptr;
617 found = 0;
618 while (!wrapped || current != tree->selected_ptr)
620 if (strncmp (current->subname, text, len) == 0)
622 tree->selected_ptr = current;
623 found = 1;
624 break;
626 current = current->next;
627 if (!current)
629 current = tree->store->tree_first;
630 wrapped = 1;
632 tree->topdiff++;
634 tree_check_focus (tree);
635 return found;
638 static void
639 tree_do_search (WTree * tree, int key)
641 size_t l;
643 l = strlen (tree->search_buffer);
644 if ((l != 0) && (key == KEY_BACKSPACE))
645 tree->search_buffer[--l] = '\0';
646 else if (key && l < sizeof (tree->search_buffer))
648 tree->search_buffer[l] = key;
649 tree->search_buffer[++l] = '\0';
652 if (!search_tree (tree, tree->search_buffer))
653 tree->search_buffer[--l] = 0;
655 show_tree (tree);
656 maybe_chdir (tree);
659 static void
660 tree_rescan (void *data)
662 char old_dir[MC_MAXPATHLEN];
663 WTree *tree = data;
664 int ret;
666 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
667 mc_chdir (tree->selected_ptr->name))
668 return;
670 tree_store_rescan (tree->selected_ptr->name);
671 ret = mc_chdir (old_dir);
674 static void
675 tree_forget (void *data)
677 WTree *tree = data;
678 if (tree->selected_ptr)
679 tree_remove_entry (tree, tree->selected_ptr->name);
682 static void
683 tree_copy (WTree * tree, const char *default_dest)
685 char msg[BUF_MEDIUM];
686 char *dest;
688 if (tree->selected_ptr == NULL)
689 return;
691 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
692 str_trunc (tree->selected_ptr->name, 50));
693 dest = input_expand_dialog (Q_ ("DialogTitle|Copy"),
694 msg, MC_HISTORY_FM_TREE_COPY, default_dest);
696 if (dest != NULL && *dest != '\0')
698 FileOpContext *ctx;
699 FileOpTotalContext *tctx;
701 ctx = file_op_context_new (OP_COPY);
702 tctx = file_op_total_context_new ();
703 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_MULTI_ITEM);
704 tctx->ask_overwrite = FALSE;
705 tctx->is_toplevel_file = FALSE;
706 copy_dir_dir (tctx, ctx, tree->selected_ptr->name, dest, TRUE, FALSE, FALSE, NULL);
707 file_op_total_context_destroy (tctx);
708 file_op_context_destroy (ctx);
711 g_free (dest);
714 static void
715 tree_move (WTree * tree, const char *default_dest)
717 char msg[BUF_MEDIUM];
718 char *dest;
719 struct stat buf;
720 FileOpContext *ctx;
721 FileOpTotalContext *tctx;
723 if (tree->selected_ptr == NULL)
724 return;
726 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
727 str_trunc (tree->selected_ptr->name, 50));
728 dest =
729 input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
731 if (dest == NULL || *dest == '\0')
733 g_free (dest);
734 return;
737 if (stat (dest, &buf))
739 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
740 unix_error_string (errno));
741 g_free (dest);
742 return;
745 if (!S_ISDIR (buf.st_mode))
747 file_error (_(" Destination \"%s\" must be a directory \n %s "), dest);
748 g_free (dest);
749 return;
752 ctx = file_op_context_new (OP_MOVE);
753 tctx = file_op_total_context_new ();
754 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
755 move_dir_dir (tctx, ctx, tree->selected_ptr->name, dest);
756 file_op_total_context_destroy (tctx);
757 file_op_context_destroy (ctx);
759 g_free (dest);
762 #if 0
763 static void
764 tree_mkdir (WTree * tree)
766 char old_dir[MC_MAXPATHLEN];
768 if (!tree->selected_ptr)
769 return;
770 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
771 return;
772 if (chdir (tree->selected_ptr->name))
773 return;
774 /* FIXME
775 mkdir_cmd (tree);
777 tree_rescan (tree);
778 chdir (old_dir);
780 #endif
782 static void
783 tree_rmdir (void *data)
785 WTree *tree = data;
786 FileOpContext *ctx;
787 FileOpTotalContext *tctx;
789 if (!tree->selected_ptr)
790 return;
792 if (confirm_delete)
794 char *buf;
795 int result;
797 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
798 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
799 g_free (buf);
800 if (result != 0)
801 return;
804 ctx = file_op_context_new (OP_DELETE);
805 tctx = file_op_total_context_new ();
807 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
808 if (erase_dir (tctx, ctx, tree->selected_ptr->name) == FILE_CONT)
809 tree_forget (tree);
810 file_op_total_context_destroy (tctx);
811 file_op_context_destroy (ctx);
814 static inline void
815 tree_move_up (WTree * tree)
817 tree_move_backward (tree, 1);
818 show_tree (tree);
819 maybe_chdir (tree);
822 static inline void
823 tree_move_down (WTree * tree)
825 tree_move_forward (tree, 1);
826 show_tree (tree);
827 maybe_chdir (tree);
830 static inline void
831 tree_move_home (WTree * tree)
833 tree_move_to_top (tree);
834 show_tree (tree);
835 maybe_chdir (tree);
838 static inline void
839 tree_move_end (WTree * tree)
841 tree_move_to_bottom (tree);
842 show_tree (tree);
843 maybe_chdir (tree);
846 static void
847 tree_move_pgup (WTree * tree)
849 tree_move_backward (tree, tlines (tree) - 1);
850 show_tree (tree);
851 maybe_chdir (tree);
854 static void
855 tree_move_pgdn (WTree * tree)
857 tree_move_forward (tree, tlines (tree) - 1);
858 show_tree (tree);
859 maybe_chdir (tree);
862 static gboolean
863 tree_move_left (WTree * tree)
865 gboolean v = FALSE;
867 if (tree_navigation_flag)
869 v = tree_move_to_parent (tree);
870 show_tree (tree);
871 maybe_chdir (tree);
874 return v;
877 static gboolean
878 tree_move_right (WTree * tree)
880 gboolean v = FALSE;
882 if (tree_navigation_flag)
884 tree_move_to_child (tree);
885 show_tree (tree);
886 maybe_chdir (tree);
887 v = TRUE;
890 return v;
893 static void
894 tree_start_search (WTree * tree)
896 gboolean i;
898 if (tree->searching)
900 if (tree->selected_ptr == tree->store->tree_last)
901 tree_move_to_top (tree);
902 else
904 /* set navigation mode temporarily to 'Static' because in
905 * dynamic navigation mode tree_move_forward will not move
906 * to a lower sublevel if necessary (sequent searches must
907 * start with the directory followed the last found directory)
909 i = tree_navigation_flag;
910 tree_navigation_flag = 0;
911 tree_move_forward (tree, 1);
912 tree_navigation_flag = i;
914 tree_do_search (tree, 0);
916 else
918 tree->searching = 1;
919 tree->search_buffer[0] = 0;
923 static void
924 tree_toggle_navig (WTree * tree)
926 tree_navigation_flag = !tree_navigation_flag;
927 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
928 tree_navigation_flag ? Q_ ("ButtonBar|Static")
929 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
932 static cb_ret_t
933 tree_execute_cmd (WTree * tree, unsigned long command)
935 cb_ret_t res = MSG_HANDLED;
937 if (command != CK_TreeStartSearch)
938 tree->searching = 0;
940 switch (command)
942 case CK_TreeHelp:
943 interactive_display (NULL, "[Directory Tree]");
944 break;
945 case CK_TreeForget:
946 tree_forget (tree);
947 break;
948 case CK_TreeToggleNav:
949 tree_toggle_navig (tree);
950 break;
951 case CK_TreeCopy:
952 tree_copy (tree, "");
953 break;
954 case CK_TreeMove:
955 tree_move (tree, "");
956 break;
957 case CK_TreeMoveUp:
958 tree_move_up (tree);
959 break;
960 case CK_TreeMoveDown:
961 tree_move_down (tree);
962 break;
963 case CK_TreeMoveHome:
964 tree_move_home (tree);
965 break;
966 case CK_TreeMoveEnd:
967 tree_move_end (tree);
968 break;
969 case CK_TreeMovePgUp:
970 tree_move_pgup (tree);
971 break;
972 case CK_TreeMovePgDn:
973 tree_move_pgdn (tree);
974 break;
975 case CK_TreeOpen:
976 tree_chdir_sel (tree);
977 break;
978 case CK_TreeRescan:
979 tree_rescan (tree);
980 break;
981 case CK_TreeStartSearch:
982 tree_start_search (tree);
983 break;
984 case CK_TreeRemove:
985 tree_rmdir (tree);
986 break;
987 default:
988 res = MSG_NOT_HANDLED;
991 show_tree (tree);
993 return res;
996 static cb_ret_t
997 tree_key (WTree * tree, int key)
999 size_t i;
1001 for (i = 0; tree_map[i].key != 0; i++)
1002 if (key == tree_map[i].key)
1003 switch (tree_map[i].command)
1005 case CK_TreeMoveLeft:
1006 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1007 case CK_TreeMoveRight:
1008 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1009 default:
1010 tree_execute_cmd (tree, tree_map[i].command);
1011 return MSG_HANDLED;
1014 if (is_abort_char (key))
1016 if (tree->is_panel)
1018 tree->searching = 0;
1019 show_tree (tree);
1020 return MSG_HANDLED; /* eat abort char */
1022 /* modal tree dialog: let upper layer see the
1023 abort character and close the dialog */
1024 return MSG_NOT_HANDLED;
1027 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1028 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE)
1030 if (tree->searching)
1032 tree_do_search (tree, key);
1033 show_tree (tree);
1034 return MSG_HANDLED;
1037 if (!command_prompt)
1039 tree_start_search (tree);
1040 tree_do_search (tree, key);
1041 return MSG_HANDLED;
1043 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
1046 return MSG_NOT_HANDLED;
1049 static void
1050 tree_frame (Dlg_head * h, WTree * tree)
1052 tty_setcolor (NORMAL_COLOR);
1053 widget_erase ((Widget *) tree);
1054 if (tree->is_panel)
1056 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines, tree->widget.cols, FALSE);
1058 if (show_mini_info)
1059 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
1060 tree->widget.x + 1, ACS_HLINE, tree->widget.cols - 2);
1064 static cb_ret_t
1065 tree_callback (Widget * w, widget_msg_t msg, int parm)
1067 WTree *tree = (WTree *) w;
1068 Dlg_head *h = tree->widget.parent;
1069 WButtonBar *b = find_buttonbar (h);
1071 switch (msg)
1073 case WIDGET_DRAW:
1074 tree_frame (h, tree);
1075 show_tree (tree);
1076 return MSG_HANDLED;
1078 case WIDGET_FOCUS:
1079 tree->active = 1;
1080 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), tree_map, (Widget *) tree);
1081 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1082 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Forget"), tree_map, (Widget *) tree);
1083 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_ ("ButtonBar|Static")
1084 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
1085 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), tree_map, (Widget *) tree);
1086 buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1087 #if 0
1088 /* FIXME: mkdir is currently defunct */
1089 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1090 #else
1091 buttonbar_clear_label (b, 7, (Widget *) tree);
1092 #endif
1093 buttonbar_set_label (b, 8, Q_ ("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1094 buttonbar_redraw (b);
1096 /* FIXME: Should find a better way of only displaying the
1097 currently selected item */
1098 show_tree (tree);
1099 return MSG_HANDLED;
1101 /* FIXME: Should find a better way of changing the color of the
1102 selected item */
1104 case WIDGET_UNFOCUS:
1105 tree->active = 0;
1106 show_tree (tree);
1107 return MSG_HANDLED;
1109 case WIDGET_KEY:
1110 return tree_key (tree, parm);
1112 case WIDGET_COMMAND:
1113 /* command from buttonbar */
1114 return tree_execute_cmd (tree, parm);
1116 case WIDGET_DESTROY:
1117 tree_destroy (tree);
1118 return MSG_HANDLED;
1120 default:
1121 return default_proc (msg, parm);
1125 WTree *
1126 tree_new (int is_panel, int y, int x, int lines, int cols)
1128 WTree *tree = g_new (WTree, 1);
1130 init_widget (&tree->widget, y, x, lines, cols, tree_callback, event_callback);
1131 tree->is_panel = is_panel;
1132 tree->selected_ptr = 0;
1134 tree->store = tree_store_get ();
1135 tree_store_add_entry_remove_hook (remove_callback, tree);
1136 tree->tree_shown = 0;
1137 tree->search_buffer[0] = 0;
1138 tree->topdiff = tree->widget.lines / 2;
1139 tree->searching = 0;
1140 tree->active = 0;
1142 /* We do not want to keep the cursor */
1143 widget_want_cursor (tree->widget, 0);
1144 load_tree (tree);
1145 return tree;
1148 void
1149 tree_chdir (WTree * tree, const char *dir)
1151 tree_entry *current;
1153 current = tree_store_whereis (dir);
1155 if (current != NULL)
1157 tree->selected_ptr = current;
1158 tree_check_focus (tree);
1162 /* Return name of the currently selected entry */
1163 char *
1164 tree_selected_name (const WTree * tree)
1166 return tree->selected_ptr->name;
1169 void
1170 sync_tree (const char *path)
1172 tree_chdir (the_tree, path);
1175 WTree *
1176 find_tree (struct Dlg_head *h)
1178 return (WTree *) find_widget_type (h, tree_callback);