Ticket #2170: Color collisions
[midnight-commander.git] / src / tree.c
blob5dcdfac173517ef2cb55018d37732f260e414ded
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) (h->color[DLG_COLOR_NORMAL])
75 #define TREE_CURRENTC(h) (h->color[DLG_COLOR_FOCUS])
77 /* Specifies the display mode: 1d or 2d */
78 static gboolean tree_navigation_flag = FALSE;
80 struct WTree
82 Widget widget;
83 struct TreeStore *store;
84 tree_entry *selected_ptr; /* The selected directory */
85 char search_buffer[MC_MAXFILENAMELEN]; /* 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)
104 ptr = ptr->prev;
105 i++;
107 *count = i;
108 return ptr;
111 static tree_entry *
112 forw_ptr (tree_entry * ptr, int *count)
114 int i = 0;
116 while (ptr && ptr->next && i < *count)
118 ptr = ptr->next;
119 i++;
121 *count = i;
122 return ptr;
125 static void
126 remove_callback (tree_entry * entry, void *data)
128 WTree *tree = data;
130 if (tree->selected_ptr == entry)
132 if (tree->selected_ptr->next)
133 tree->selected_ptr = tree->selected_ptr->next;
134 else
135 tree->selected_ptr = tree->selected_ptr->prev;
139 /* Save the ~/.mc/Tree file */
140 static void
141 save_tree (WTree * tree)
143 int error;
144 char *tree_name;
146 (void) tree;
147 error = tree_store_save ();
150 if (error)
152 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR, MC_TREESTORE_FILE, (char *) NULL);
153 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
154 unix_error_string (error));
155 g_free (tree_name);
159 static void
160 tree_remove_entry (WTree * tree, char *name)
162 (void) tree;
163 tree_store_remove_entry (name);
166 static void
167 tree_destroy (WTree * tree)
169 tree_store_remove_entry_remove_hook (remove_callback);
170 save_tree (tree);
172 g_free (tree->tree_shown);
173 tree->tree_shown = 0;
174 tree->selected_ptr = NULL;
177 /* Loads the .mc.tree file */
178 static void
179 load_tree (WTree * tree)
181 tree_store_load ();
183 tree->selected_ptr = tree->store->tree_first;
184 tree_chdir (tree, home_dir);
187 static void
188 tree_show_mini_info (WTree * tree, int tree_lines, int tree_cols)
190 Dlg_head *h = tree->widget.owner;
191 int line;
193 /* Show mini info */
194 if (tree->is_panel)
196 if (!show_mini_info)
197 return;
198 line = tree_lines + 2;
200 else
201 line = tree_lines + 1;
203 if (tree->searching)
205 /* Show search string */
206 tty_setcolor (INPUT_COLOR);
207 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
208 widget_move (&tree->widget, line, 1);
209 tty_print_char (PATH_SEP);
210 tty_print_string (str_fit_to_term (tree->search_buffer, tree_cols - 2, J_LEFT_FIT));
211 tty_print_char (' ');
213 else
215 /* Show full name of selected directory */
216 tty_setcolor (tree->is_panel ? NORMAL_COLOR : TREE_NORMALC (h));
217 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
218 widget_move (&tree->widget, line, 1);
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.owner;
227 tree_entry *current;
228 int i, j, topsublevel;
229 int x = 0, y = 0;
230 int tree_lines, tree_cols;
232 /* Initialize */
233 tree_lines = tlines (tree);
234 tree_cols = tree->widget.cols;
236 widget_move ((Widget *) tree, y, x);
237 if (tree->is_panel)
239 tree_cols -= 2;
240 x = y = 1;
243 g_free (tree->tree_shown);
244 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
246 if (tree->store->tree_first)
247 topsublevel = tree->store->tree_first->sublevel;
248 else
249 topsublevel = 0;
250 if (!tree->selected_ptr)
252 tree->selected_ptr = tree->store->tree_first;
253 tree->topdiff = 0;
255 current = tree->selected_ptr;
257 /* Calculate the directory which is to be shown on the topmost line */
258 if (!tree_navigation_flag)
259 current = back_ptr (current, &tree->topdiff);
260 else
262 i = 0;
263 while (current->prev && i < tree->topdiff)
265 current = current->prev;
266 if (current->sublevel < tree->selected_ptr->sublevel)
268 if (strncmp (current->name, tree->selected_ptr->name, strlen (current->name)) == 0)
269 i++;
271 else if (current->sublevel == tree->selected_ptr->sublevel)
273 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--);
274 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
275 i++;
277 else if (current->sublevel == tree->selected_ptr->sublevel + 1
278 && strlen (tree->selected_ptr->name) > 1)
280 if (strncmp (current->name, tree->selected_ptr->name,
281 strlen (tree->selected_ptr->name)) == 0)
282 i++;
285 tree->topdiff = i;
288 /* Loop for every line */
289 for (i = 0; i < tree_lines; i++)
291 tty_setcolor (tree->is_panel ? NORMAL_COLOR : TREE_NORMALC (h));
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 == NULL)
297 continue;
299 if (tree->is_panel)
300 tty_setcolor (tree->active && current == tree->selected_ptr
301 ? SELECTED_COLOR : NORMAL_COLOR);
302 else
303 tty_setcolor (current == tree->selected_ptr ? TREE_CURRENTC (h) : TREE_NORMALC (h));
305 tree->tree_shown[i] = current;
306 if (current->sublevel == topsublevel)
308 /* Show full name */
309 tty_print_string (str_fit_to_term (current->name, tree_cols + (tree->is_panel ? 0 : 1), J_LEFT_FIT));
311 else
313 /* Sub level directory */
314 tty_set_alt_charset (TRUE);
316 /* Output branch parts */
317 for (j = 0; j < current->sublevel - topsublevel - 1; j++)
319 if (tree_cols - 8 - 3 * j < 9)
320 break;
321 tty_print_char (' ');
322 if (current->submask & (1 << (j + topsublevel + 1)))
323 tty_print_char (ACS_VLINE);
324 else
325 tty_print_char (' ');
326 tty_print_char (' ');
328 tty_print_char (' ');
329 j++;
330 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
331 tty_print_char (ACS_LLCORNER);
332 else
333 tty_print_char (ACS_LTEE);
334 tty_print_char (ACS_HLINE);
335 tty_set_alt_charset (FALSE);
337 /* Show sub-name */
338 tty_print_char (' ');
339 tty_print_string (str_fit_to_term (current->subname, tree_cols - x - 3 * j, J_LEFT_FIT));
342 /* Calculate the next value for current */
343 current = current->next;
344 if (tree_navigation_flag)
346 while (current != NULL)
348 if (current->sublevel < tree->selected_ptr->sublevel)
350 if (strncmp (current->name, tree->selected_ptr->name,
351 strlen (current->name)) == 0)
352 break;
354 else if (current->sublevel == tree->selected_ptr->sublevel)
356 for (j = strlen (current->name) - 1; current->name[j] != PATH_SEP; j--)
358 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
359 break;
361 else if (current->sublevel == tree->selected_ptr->sublevel + 1
362 && strlen (tree->selected_ptr->name) > 1)
364 if (strncmp (current->name, tree->selected_ptr->name,
365 strlen (tree->selected_ptr->name)) == 0)
366 break;
368 current = current->next;
373 tree_show_mini_info (tree, tree_lines, tree_cols);
376 static void
377 tree_check_focus (WTree * tree)
379 if (tree->topdiff < 3)
380 tree->topdiff = 3;
381 else if (tree->topdiff >= tlines (tree) - 3)
382 tree->topdiff = tlines (tree) - 3 - 1;
385 static void
386 tree_move_backward (WTree * tree, int i)
388 if (!tree_navigation_flag)
389 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
390 else
392 tree_entry *current;
393 int j = 0;
395 current = tree->selected_ptr;
396 while (j < i && current->prev && current->prev->sublevel >= tree->selected_ptr->sublevel)
398 current = current->prev;
399 if (current->sublevel == tree->selected_ptr->sublevel)
401 tree->selected_ptr = current;
402 j++;
405 i = j;
408 tree->topdiff -= i;
409 tree_check_focus (tree);
412 static void
413 tree_move_forward (WTree * tree, int i)
415 if (!tree_navigation_flag)
416 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
417 else
419 tree_entry *current;
420 int j = 0;
422 current = tree->selected_ptr;
423 while (j < i && current->next && current->next->sublevel >= tree->selected_ptr->sublevel)
425 current = current->next;
426 if (current->sublevel == tree->selected_ptr->sublevel)
428 tree->selected_ptr = current;
429 j++;
432 i = j;
435 tree->topdiff += i;
436 tree_check_focus (tree);
439 static void
440 tree_move_to_child (WTree * tree)
442 tree_entry *current;
444 /* Do we have a starting point? */
445 if (!tree->selected_ptr)
446 return;
447 /* Take the next entry */
448 current = tree->selected_ptr->next;
449 /* Is it the child of the selected entry */
450 if (current && current->sublevel > tree->selected_ptr->sublevel)
452 /* Yes -> select this entry */
453 tree->selected_ptr = current;
454 tree->topdiff++;
455 tree_check_focus (tree);
457 else
459 /* No -> rescan and try again */
460 tree_rescan (tree);
461 current = tree->selected_ptr->next;
462 if (current && current->sublevel > tree->selected_ptr->sublevel)
464 tree->selected_ptr = current;
465 tree->topdiff++;
466 tree_check_focus (tree);
471 static gboolean
472 tree_move_to_parent (WTree * tree)
474 tree_entry *current;
475 tree_entry *old;
477 if (!tree->selected_ptr)
478 return FALSE;
480 old = tree->selected_ptr;
481 current = tree->selected_ptr->prev;
482 while (current && current->sublevel >= tree->selected_ptr->sublevel)
484 current = current->prev;
485 tree->topdiff--;
487 if (!current)
488 current = tree->store->tree_first;
489 tree->selected_ptr = current;
490 tree_check_focus (tree);
491 return tree->selected_ptr != old;
494 static void
495 tree_move_to_top (WTree * tree)
497 tree->selected_ptr = tree->store->tree_first;
498 tree->topdiff = 0;
501 static void
502 tree_move_to_bottom (WTree * tree)
504 tree->selected_ptr = tree->store->tree_last;
505 tree->topdiff = tlines (tree) - 3 - 1;
508 /* Handle mouse click */
509 static void
510 tree_event (WTree * tree, int y)
512 if (tree->tree_shown[y])
514 tree->selected_ptr = tree->tree_shown[y];
515 tree->topdiff = y;
517 show_tree (tree);
520 static void
521 tree_chdir_sel (WTree * tree)
523 if (!tree->is_panel)
524 return;
526 change_panel ();
528 if (do_cd (tree->selected_ptr->name, cd_exact))
529 select_item (current_panel);
530 else
531 message (D_ERROR, MSG_ERROR, _("Cannot chdir to \"%s\"\n%s"),
532 tree->selected_ptr->name, unix_error_string (errno));
534 change_panel ();
535 show_tree (tree);
538 static void
539 maybe_chdir (WTree * tree)
541 if (xtree_mode && tree->is_panel && is_idle ())
542 tree_chdir_sel (tree);
545 /* Mouse callback */
546 static int
547 event_callback (Gpm_Event * event, void *data)
549 WTree *tree = data;
551 /* rest of the upper frame, the menu is invisible - call menu */
552 if (tree->is_panel && (event->type & GPM_DOWN) && event->y == 1 && !menubar_visible)
554 event->x += tree->widget.x;
555 return the_menubar->widget.mouse (event, the_menubar);
558 if (!(event->type & GPM_UP))
559 return MOU_NORMAL;
561 if (tree->is_panel)
562 event->y--;
564 event->y--;
566 if (!tree->active)
567 change_panel ();
569 if (event->y < 0)
571 tree_move_backward (tree, tlines (tree) - 1);
572 show_tree (tree);
574 else if (event->y >= tlines (tree))
576 tree_move_forward (tree, tlines (tree) - 1);
577 show_tree (tree);
579 else
581 tree_event (tree, event->y);
582 if ((event->type & (GPM_UP | GPM_DOUBLE)) == (GPM_UP | GPM_DOUBLE))
584 tree_chdir_sel (tree);
587 return MOU_NORMAL;
590 /* Search tree for text */
591 static int
592 search_tree (WTree * tree, char *text)
594 tree_entry *current;
595 int len;
596 int wrapped = 0;
597 int found = 0;
599 len = strlen (text);
600 current = tree->selected_ptr;
601 found = 0;
602 while (!wrapped || current != tree->selected_ptr)
604 if (strncmp (current->subname, text, len) == 0)
606 tree->selected_ptr = current;
607 found = 1;
608 break;
610 current = current->next;
611 if (!current)
613 current = tree->store->tree_first;
614 wrapped = 1;
616 tree->topdiff++;
618 tree_check_focus (tree);
619 return found;
622 static void
623 tree_do_search (WTree * tree, int key)
625 size_t l;
627 l = strlen (tree->search_buffer);
628 if ((l != 0) && (key == KEY_BACKSPACE))
629 tree->search_buffer[--l] = '\0';
630 else if (key && l < sizeof (tree->search_buffer))
632 tree->search_buffer[l] = key;
633 tree->search_buffer[++l] = '\0';
636 if (!search_tree (tree, tree->search_buffer))
637 tree->search_buffer[--l] = 0;
639 show_tree (tree);
640 maybe_chdir (tree);
643 static void
644 tree_rescan (void *data)
646 char old_dir[MC_MAXPATHLEN];
647 WTree *tree = data;
648 int ret;
650 if (tree->selected_ptr == NULL || mc_get_current_wd (old_dir, MC_MAXPATHLEN) == NULL
651 || mc_chdir (tree->selected_ptr->name))
652 return;
654 tree_store_rescan (tree->selected_ptr->name);
655 ret = mc_chdir (old_dir);
658 static void
659 tree_forget (void *data)
661 WTree *tree = data;
662 if (tree->selected_ptr)
663 tree_remove_entry (tree, tree->selected_ptr->name);
666 static void
667 tree_copy (WTree * tree, const char *default_dest)
669 char msg[BUF_MEDIUM];
670 char *dest;
672 if (tree->selected_ptr == NULL)
673 return;
675 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
676 str_trunc (tree->selected_ptr->name, 50));
677 dest = input_expand_dialog (Q_ ("DialogTitle|Copy"),
678 msg, MC_HISTORY_FM_TREE_COPY, default_dest);
680 if (dest != NULL && *dest != '\0')
682 FileOpContext *ctx;
683 FileOpTotalContext *tctx;
685 ctx = file_op_context_new (OP_COPY);
686 tctx = file_op_total_context_new ();
687 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_MULTI_ITEM);
688 tctx->ask_overwrite = FALSE;
689 tctx->is_toplevel_file = FALSE;
690 copy_dir_dir (tctx, ctx, tree->selected_ptr->name, dest, TRUE, FALSE, FALSE, NULL);
691 file_op_total_context_destroy (tctx);
692 file_op_context_destroy (ctx);
695 g_free (dest);
698 static void
699 tree_move (WTree * tree, const char *default_dest)
701 char msg[BUF_MEDIUM];
702 char *dest;
703 struct stat buf;
704 FileOpContext *ctx;
705 FileOpTotalContext *tctx;
707 if (tree->selected_ptr == NULL)
708 return;
710 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
711 str_trunc (tree->selected_ptr->name, 50));
712 dest =
713 input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
715 if (dest == NULL || *dest == '\0')
717 g_free (dest);
718 return;
721 if (stat (dest, &buf))
723 message (D_ERROR, MSG_ERROR, _("Cannot stat the destination\n%s"),
724 unix_error_string (errno));
725 g_free (dest);
726 return;
729 if (!S_ISDIR (buf.st_mode))
731 file_error (_("Destination \"%s\" must be a directory\n%s"), dest);
732 g_free (dest);
733 return;
736 ctx = file_op_context_new (OP_MOVE);
737 tctx = file_op_total_context_new ();
738 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
739 move_dir_dir (tctx, ctx, tree->selected_ptr->name, dest);
740 file_op_total_context_destroy (tctx);
741 file_op_context_destroy (ctx);
743 g_free (dest);
746 #if 0
747 static void
748 tree_mkdir (WTree * tree)
750 char old_dir[MC_MAXPATHLEN];
752 if (!tree->selected_ptr)
753 return;
754 if (mc_get_current_wd (old_dir, MC_MAXPATHLEN) == NULL)
755 return;
756 if (chdir (tree->selected_ptr->name))
757 return;
758 /* FIXME
759 mkdir_cmd (tree);
761 tree_rescan (tree);
762 chdir (old_dir);
764 #endif
766 static void
767 tree_rmdir (void *data)
769 WTree *tree = data;
770 FileOpContext *ctx;
771 FileOpTotalContext *tctx;
773 if (!tree->selected_ptr)
774 return;
776 if (confirm_delete)
778 char *buf;
779 int result;
781 buf = g_strdup_printf (_("Delete %s?"), tree->selected_ptr->name);
782 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
783 g_free (buf);
784 if (result != 0)
785 return;
788 ctx = file_op_context_new (OP_DELETE);
789 tctx = file_op_total_context_new ();
791 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
792 if (erase_dir (tctx, ctx, tree->selected_ptr->name) == FILE_CONT)
793 tree_forget (tree);
794 file_op_total_context_destroy (tctx);
795 file_op_context_destroy (ctx);
798 static inline void
799 tree_move_up (WTree * tree)
801 tree_move_backward (tree, 1);
802 show_tree (tree);
803 maybe_chdir (tree);
806 static inline void
807 tree_move_down (WTree * tree)
809 tree_move_forward (tree, 1);
810 show_tree (tree);
811 maybe_chdir (tree);
814 static inline void
815 tree_move_home (WTree * tree)
817 tree_move_to_top (tree);
818 show_tree (tree);
819 maybe_chdir (tree);
822 static inline void
823 tree_move_end (WTree * tree)
825 tree_move_to_bottom (tree);
826 show_tree (tree);
827 maybe_chdir (tree);
830 static void
831 tree_move_pgup (WTree * tree)
833 tree_move_backward (tree, tlines (tree) - 1);
834 show_tree (tree);
835 maybe_chdir (tree);
838 static void
839 tree_move_pgdn (WTree * tree)
841 tree_move_forward (tree, tlines (tree) - 1);
842 show_tree (tree);
843 maybe_chdir (tree);
846 static gboolean
847 tree_move_left (WTree * tree)
849 gboolean v = FALSE;
851 if (tree_navigation_flag)
853 v = tree_move_to_parent (tree);
854 show_tree (tree);
855 maybe_chdir (tree);
858 return v;
861 static gboolean
862 tree_move_right (WTree * tree)
864 gboolean v = FALSE;
866 if (tree_navigation_flag)
868 tree_move_to_child (tree);
869 show_tree (tree);
870 maybe_chdir (tree);
871 v = TRUE;
874 return v;
877 static void
878 tree_start_search (WTree * tree)
880 gboolean i;
882 if (tree->searching)
884 if (tree->selected_ptr == tree->store->tree_last)
885 tree_move_to_top (tree);
886 else
888 /* set navigation mode temporarily to 'Static' because in
889 * dynamic navigation mode tree_move_forward will not move
890 * to a lower sublevel if necessary (sequent searches must
891 * start with the directory followed the last found directory)
893 i = tree_navigation_flag;
894 tree_navigation_flag = 0;
895 tree_move_forward (tree, 1);
896 tree_navigation_flag = i;
898 tree_do_search (tree, 0);
900 else
902 tree->searching = 1;
903 tree->search_buffer[0] = 0;
907 static void
908 tree_toggle_navig (WTree * tree)
910 tree_navigation_flag = !tree_navigation_flag;
911 buttonbar_set_label (find_buttonbar (tree->widget.owner), 4,
912 tree_navigation_flag ? Q_ ("ButtonBar|Static")
913 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
916 static cb_ret_t
917 tree_execute_cmd (WTree * tree, unsigned long command)
919 cb_ret_t res = MSG_HANDLED;
921 if (command != CK_TreeStartSearch)
922 tree->searching = 0;
924 switch (command)
926 case CK_TreeHelp:
927 interactive_display (NULL, "[Directory Tree]");
928 break;
929 case CK_TreeForget:
930 tree_forget (tree);
931 break;
932 case CK_TreeToggleNav:
933 tree_toggle_navig (tree);
934 break;
935 case CK_TreeCopy:
936 tree_copy (tree, "");
937 break;
938 case CK_TreeMove:
939 tree_move (tree, "");
940 break;
941 case CK_TreeMoveUp:
942 tree_move_up (tree);
943 break;
944 case CK_TreeMoveDown:
945 tree_move_down (tree);
946 break;
947 case CK_TreeMoveHome:
948 tree_move_home (tree);
949 break;
950 case CK_TreeMoveEnd:
951 tree_move_end (tree);
952 break;
953 case CK_TreeMovePgUp:
954 tree_move_pgup (tree);
955 break;
956 case CK_TreeMovePgDn:
957 tree_move_pgdn (tree);
958 break;
959 case CK_TreeOpen:
960 tree_chdir_sel (tree);
961 break;
962 case CK_TreeRescan:
963 tree_rescan (tree);
964 break;
965 case CK_TreeStartSearch:
966 tree_start_search (tree);
967 break;
968 case CK_TreeRemove:
969 tree_rmdir (tree);
970 break;
971 default:
972 res = MSG_NOT_HANDLED;
975 show_tree (tree);
977 return res;
980 static cb_ret_t
981 tree_key (WTree * tree, int key)
983 size_t i;
985 for (i = 0; tree_map[i].key != 0; i++)
986 if (key == tree_map[i].key)
987 switch (tree_map[i].command)
989 case CK_TreeMoveLeft:
990 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
991 case CK_TreeMoveRight:
992 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
993 default:
994 tree_execute_cmd (tree, tree_map[i].command);
995 return MSG_HANDLED;
998 if (is_abort_char (key))
1000 if (tree->is_panel)
1002 tree->searching = 0;
1003 show_tree (tree);
1004 return MSG_HANDLED; /* eat abort char */
1006 /* modal tree dialog: let upper layer see the
1007 abort character and close the dialog */
1008 return MSG_NOT_HANDLED;
1011 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1012 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE)
1014 if (tree->searching)
1016 tree_do_search (tree, key);
1017 show_tree (tree);
1018 return MSG_HANDLED;
1021 if (!command_prompt)
1023 tree_start_search (tree);
1024 tree_do_search (tree, key);
1025 return MSG_HANDLED;
1027 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
1030 return MSG_NOT_HANDLED;
1033 static void
1034 tree_frame (Dlg_head * h, WTree * tree)
1036 tty_setcolor (NORMAL_COLOR);
1037 widget_erase ((Widget *) tree);
1038 if (tree->is_panel)
1040 const char *title = _("Directory tree");
1041 const int len = str_term_width1 (title);
1043 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines, tree->widget.cols, FALSE);
1045 widget_move (&tree->widget, 0, (tree->widget.cols - len - 2)/2);
1046 tty_printf (" %s ", title);
1048 if (show_mini_info)
1049 widget_move (&tree->widget, tlines (tree) + 1, 0);
1050 tty_print_alt_char (ACS_LTEE, FALSE);
1051 widget_move (&tree->widget, tlines (tree) + 1, tree->widget.cols - 1);
1052 tty_print_alt_char (ACS_RTEE, FALSE);
1053 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
1054 tree->widget.x + 1, ACS_HLINE, tree->widget.cols - 2);
1058 static cb_ret_t
1059 tree_callback (Widget * w, widget_msg_t msg, int parm)
1061 WTree *tree = (WTree *) w;
1062 Dlg_head *h = tree->widget.owner;
1063 WButtonBar *b = find_buttonbar (h);
1065 switch (msg)
1067 case WIDGET_DRAW:
1068 tree_frame (h, tree);
1069 show_tree (tree);
1070 return MSG_HANDLED;
1072 case WIDGET_FOCUS:
1073 tree->active = 1;
1074 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), tree_map, (Widget *) tree);
1075 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1076 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Forget"), tree_map, (Widget *) tree);
1077 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_ ("ButtonBar|Static")
1078 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
1079 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), tree_map, (Widget *) tree);
1080 buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1081 #if 0
1082 /* FIXME: mkdir is currently defunct */
1083 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1084 #else
1085 buttonbar_clear_label (b, 7, (Widget *) tree);
1086 #endif
1087 buttonbar_set_label (b, 8, Q_ ("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1088 buttonbar_redraw (b);
1090 /* FIXME: Should find a better way of only displaying the
1091 currently selected item */
1092 show_tree (tree);
1093 return MSG_HANDLED;
1095 /* FIXME: Should find a better way of changing the color of the
1096 selected item */
1098 case WIDGET_UNFOCUS:
1099 tree->active = 0;
1100 tree->searching = 0;
1101 show_tree (tree);
1102 return MSG_HANDLED;
1104 case WIDGET_KEY:
1105 return tree_key (tree, parm);
1107 case WIDGET_COMMAND:
1108 /* command from buttonbar */
1109 return tree_execute_cmd (tree, parm);
1111 case WIDGET_DESTROY:
1112 tree_destroy (tree);
1113 return MSG_HANDLED;
1115 default:
1116 return default_proc (msg, parm);
1120 WTree *
1121 tree_new (int y, int x, int lines, int cols, gboolean is_panel)
1123 WTree *tree = g_new (WTree, 1);
1125 init_widget (&tree->widget, y, x, lines, cols, tree_callback, event_callback);
1126 tree->is_panel = is_panel;
1127 tree->selected_ptr = 0;
1129 tree->store = tree_store_get ();
1130 tree_store_add_entry_remove_hook (remove_callback, tree);
1131 tree->tree_shown = 0;
1132 tree->search_buffer[0] = 0;
1133 tree->topdiff = tree->widget.lines / 2;
1134 tree->searching = 0;
1135 tree->active = 0;
1137 /* We do not want to keep the cursor */
1138 widget_want_cursor (tree->widget, 0);
1139 load_tree (tree);
1140 return tree;
1143 void
1144 tree_chdir (WTree * tree, const char *dir)
1146 tree_entry *current;
1148 current = tree_store_whereis (dir);
1150 if (current != NULL)
1152 tree->selected_ptr = current;
1153 tree_check_focus (tree);
1157 /* Return name of the currently selected entry */
1158 char *
1159 tree_selected_name (const WTree * tree)
1161 return tree->selected_ptr->name;
1164 void
1165 sync_tree (const char *path)
1167 tree_chdir (the_tree, path);
1170 WTree *
1171 find_tree (struct Dlg_head *h)
1173 return (WTree *) find_widget_type (h, tree_callback);