Ticket #2097: ChangeLog in its current form does not strictly make any sense
[midnight-commander.git] / src / tree.c
blob7df35eacbd0b7c7aeb898c3392e9713a1a53b2f8
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;
666 int ret;
668 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
669 mc_chdir (tree->selected_ptr->name))
670 return;
672 tree_store_rescan (tree->selected_ptr->name);
673 ret = mc_chdir (old_dir);
676 static void
677 tree_forget (void *data)
679 WTree *tree = data;
680 if (tree->selected_ptr)
681 tree_remove_entry (tree, tree->selected_ptr->name);
684 static void
685 tree_copy (WTree * tree, const char *default_dest)
687 char msg[BUF_MEDIUM];
688 char *dest;
690 if (tree->selected_ptr == NULL)
691 return;
693 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
694 str_trunc (tree->selected_ptr->name, 50));
695 dest = input_expand_dialog (Q_ ("DialogTitle|Copy"),
696 msg, MC_HISTORY_FM_TREE_COPY, default_dest);
698 if (dest != NULL && *dest != '\0')
700 FileOpContext *ctx;
701 FileOpTotalContext *tctx;
703 ctx = file_op_context_new (OP_COPY);
704 tctx = file_op_total_context_new ();
705 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_MULTI_ITEM);
706 tctx->ask_overwrite = FALSE;
707 tctx->is_toplevel_file = FALSE;
708 copy_dir_dir (tctx, ctx, tree->selected_ptr->name, dest, TRUE, FALSE, FALSE, NULL);
709 file_op_total_context_destroy (tctx);
710 file_op_context_destroy (ctx);
713 g_free (dest);
716 static void
717 tree_move (WTree * tree, const char *default_dest)
719 char msg[BUF_MEDIUM];
720 char *dest;
721 struct stat buf;
722 FileOpContext *ctx;
723 FileOpTotalContext *tctx;
725 if (tree->selected_ptr == NULL)
726 return;
728 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
729 str_trunc (tree->selected_ptr->name, 50));
730 dest =
731 input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
733 if (dest == NULL || *dest == '\0')
735 g_free (dest);
736 return;
739 if (stat (dest, &buf))
741 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
742 unix_error_string (errno));
743 g_free (dest);
744 return;
747 if (!S_ISDIR (buf.st_mode))
749 file_error (_(" Destination \"%s\" must be a directory \n %s "), dest);
750 g_free (dest);
751 return;
754 ctx = file_op_context_new (OP_MOVE);
755 tctx = file_op_total_context_new ();
756 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
757 move_dir_dir (tctx, ctx, tree->selected_ptr->name, dest);
758 file_op_total_context_destroy (tctx);
759 file_op_context_destroy (ctx);
761 g_free (dest);
764 #if 0
765 static void
766 tree_mkdir (WTree * tree)
768 char old_dir[MC_MAXPATHLEN];
770 if (!tree->selected_ptr)
771 return;
772 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
773 return;
774 if (chdir (tree->selected_ptr->name))
775 return;
776 /* FIXME
777 mkdir_cmd (tree);
779 tree_rescan (tree);
780 chdir (old_dir);
782 #endif
784 static void
785 tree_rmdir (void *data)
787 WTree *tree = data;
788 FileOpContext *ctx;
789 FileOpTotalContext *tctx;
791 if (!tree->selected_ptr)
792 return;
794 if (confirm_delete)
796 char *buf;
797 int result;
799 buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
800 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
801 g_free (buf);
802 if (result != 0)
803 return;
806 ctx = file_op_context_new (OP_DELETE);
807 tctx = file_op_total_context_new ();
809 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
810 if (erase_dir (tctx, ctx, tree->selected_ptr->name) == FILE_CONT)
811 tree_forget (tree);
812 file_op_total_context_destroy (tctx);
813 file_op_context_destroy (ctx);
816 static inline void
817 tree_move_up (WTree * tree)
819 tree_move_backward (tree, 1);
820 show_tree (tree);
821 maybe_chdir (tree);
824 static inline void
825 tree_move_down (WTree * tree)
827 tree_move_forward (tree, 1);
828 show_tree (tree);
829 maybe_chdir (tree);
832 static inline void
833 tree_move_home (WTree * tree)
835 tree_move_to_top (tree);
836 show_tree (tree);
837 maybe_chdir (tree);
840 static inline void
841 tree_move_end (WTree * tree)
843 tree_move_to_bottom (tree);
844 show_tree (tree);
845 maybe_chdir (tree);
848 static void
849 tree_move_pgup (WTree * tree)
851 tree_move_backward (tree, tlines (tree) - 1);
852 show_tree (tree);
853 maybe_chdir (tree);
856 static void
857 tree_move_pgdn (WTree * tree)
859 tree_move_forward (tree, tlines (tree) - 1);
860 show_tree (tree);
861 maybe_chdir (tree);
864 static gboolean
865 tree_move_left (WTree * tree)
867 gboolean v = FALSE;
869 if (tree_navigation_flag)
871 v = tree_move_to_parent (tree);
872 show_tree (tree);
873 maybe_chdir (tree);
876 return v;
879 static gboolean
880 tree_move_right (WTree * tree)
882 gboolean v = FALSE;
884 if (tree_navigation_flag)
886 tree_move_to_child (tree);
887 show_tree (tree);
888 maybe_chdir (tree);
889 v = TRUE;
892 return v;
895 static void
896 tree_start_search (WTree * tree)
898 gboolean i;
900 if (tree->searching)
902 if (tree->selected_ptr == tree->store->tree_last)
903 tree_move_to_top (tree);
904 else
906 /* set navigation mode temporarily to 'Static' because in
907 * dynamic navigation mode tree_move_forward will not move
908 * to a lower sublevel if necessary (sequent searches must
909 * start with the directory followed the last found directory)
911 i = tree_navigation_flag;
912 tree_navigation_flag = 0;
913 tree_move_forward (tree, 1);
914 tree_navigation_flag = i;
916 tree_do_search (tree, 0);
918 else
920 tree->searching = 1;
921 tree->search_buffer[0] = 0;
925 static void
926 tree_toggle_navig (WTree * tree)
928 tree_navigation_flag = !tree_navigation_flag;
929 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
930 tree_navigation_flag ? Q_ ("ButtonBar|Static")
931 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
934 static cb_ret_t
935 tree_execute_cmd (WTree * tree, unsigned long command)
937 cb_ret_t res = MSG_HANDLED;
939 if (command != CK_TreeStartSearch)
940 tree->searching = 0;
942 switch (command)
944 case CK_TreeHelp:
945 interactive_display (NULL, "[Directory Tree]");
946 break;
947 case CK_TreeForget:
948 tree_forget (tree);
949 break;
950 case CK_TreeToggleNav:
951 tree_toggle_navig (tree);
952 break;
953 case CK_TreeCopy:
954 tree_copy (tree, "");
955 break;
956 case CK_TreeMove:
957 tree_move (tree, "");
958 break;
959 case CK_TreeMoveUp:
960 tree_move_up (tree);
961 break;
962 case CK_TreeMoveDown:
963 tree_move_down (tree);
964 break;
965 case CK_TreeMoveHome:
966 tree_move_home (tree);
967 break;
968 case CK_TreeMoveEnd:
969 tree_move_end (tree);
970 break;
971 case CK_TreeMovePgUp:
972 tree_move_pgup (tree);
973 break;
974 case CK_TreeMovePgDn:
975 tree_move_pgdn (tree);
976 break;
977 case CK_TreeOpen:
978 tree_chdir_sel (tree);
979 break;
980 case CK_TreeRescan:
981 tree_rescan (tree);
982 break;
983 case CK_TreeStartSearch:
984 tree_start_search (tree);
985 break;
986 case CK_TreeRemove:
987 tree_rmdir (tree);
988 break;
989 default:
990 res = MSG_NOT_HANDLED;
993 show_tree (tree);
995 return res;
998 static cb_ret_t
999 tree_key (WTree * tree, int key)
1001 size_t i;
1003 for (i = 0; tree_map[i].key != 0; i++)
1004 if (key == tree_map[i].key)
1005 switch (tree_map[i].command)
1007 case CK_TreeMoveLeft:
1008 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1009 case CK_TreeMoveRight:
1010 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
1011 default:
1012 tree_execute_cmd (tree, tree_map[i].command);
1013 return MSG_HANDLED;
1016 if (is_abort_char (key))
1018 if (tree->is_panel)
1020 tree->searching = 0;
1021 show_tree (tree);
1022 return MSG_HANDLED; /* eat abort char */
1024 /* modal tree dialog: let upper layer see the
1025 abort character and close the dialog */
1026 return MSG_NOT_HANDLED;
1029 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1030 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE)
1032 if (tree->searching)
1034 tree_do_search (tree, key);
1035 show_tree (tree);
1036 return MSG_HANDLED;
1039 if (!command_prompt)
1041 tree_start_search (tree);
1042 tree_do_search (tree, key);
1043 return MSG_HANDLED;
1045 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
1048 return MSG_NOT_HANDLED;
1051 static void
1052 tree_frame (Dlg_head * h, WTree * tree)
1054 tty_setcolor (NORMAL_COLOR);
1055 widget_erase ((Widget *) tree);
1056 if (tree->is_panel)
1058 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines, tree->widget.cols, FALSE);
1060 if (show_mini_info)
1061 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
1062 tree->widget.x + 1, ACS_HLINE, tree->widget.cols - 2);
1066 static cb_ret_t
1067 tree_callback (Widget * w, widget_msg_t msg, int parm)
1069 WTree *tree = (WTree *) w;
1070 Dlg_head *h = tree->widget.parent;
1071 WButtonBar *b = find_buttonbar (h);
1073 switch (msg)
1075 case WIDGET_DRAW:
1076 tree_frame (h, tree);
1077 show_tree (tree);
1078 return MSG_HANDLED;
1080 case WIDGET_FOCUS:
1081 tree->active = 1;
1082 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), tree_map, (Widget *) tree);
1083 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1084 buttonbar_set_label (b, 3, Q_ ("ButtonBar|Forget"), tree_map, (Widget *) tree);
1085 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_ ("ButtonBar|Static")
1086 : Q_ ("ButtonBar|Dynamc"), tree_map, (Widget *) tree);
1087 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Copy"), tree_map, (Widget *) tree);
1088 buttonbar_set_label (b, 6, Q_ ("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1089 #if 0
1090 /* FIXME: mkdir is currently defunct */
1091 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1092 #else
1093 buttonbar_clear_label (b, 7, (Widget *) tree);
1094 #endif
1095 buttonbar_set_label (b, 8, Q_ ("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1096 buttonbar_redraw (b);
1098 /* FIXME: Should find a better way of only displaying the
1099 currently selected item */
1100 show_tree (tree);
1101 return MSG_HANDLED;
1103 /* FIXME: Should find a better way of changing the color of the
1104 selected item */
1106 case WIDGET_UNFOCUS:
1107 tree->active = 0;
1108 show_tree (tree);
1109 return MSG_HANDLED;
1111 case WIDGET_KEY:
1112 return tree_key (tree, parm);
1114 case WIDGET_COMMAND:
1115 /* command from buttonbar */
1116 return tree_execute_cmd (tree, parm);
1118 case WIDGET_DESTROY:
1119 tree_destroy (tree);
1120 return MSG_HANDLED;
1122 default:
1123 return default_proc (msg, parm);
1127 WTree *
1128 tree_new (int is_panel, int y, int x, int lines, int cols)
1130 WTree *tree = g_new (WTree, 1);
1132 init_widget (&tree->widget, y, x, lines, cols, tree_callback, event_callback);
1133 tree->is_panel = is_panel;
1134 tree->selected_ptr = 0;
1136 tree->store = tree_store_get ();
1137 tree_store_add_entry_remove_hook (remove_callback, tree);
1138 tree->tree_shown = 0;
1139 tree->search_buffer[0] = 0;
1140 tree->topdiff = tree->widget.lines / 2;
1141 tree->searching = 0;
1142 tree->active = 0;
1144 /* We do not want to keep the cursor */
1145 widget_want_cursor (tree->widget, 0);
1146 load_tree (tree);
1147 return tree;
1150 void
1151 tree_chdir (WTree * tree, const char *dir)
1153 tree_entry *current;
1155 current = tree_store_whereis (dir);
1157 if (current != NULL)
1159 tree->selected_ptr = current;
1160 tree_check_focus (tree);
1164 /* Return name of the currently selected entry */
1165 char *
1166 tree_selected_name (const WTree * tree)
1168 return tree->selected_ptr->name;
1171 void
1172 sync_tree (const char *path)
1174 tree_chdir (the_tree, path);
1177 WTree *
1178 find_tree (struct Dlg_head *h)
1180 return (WTree *) find_widget_type (h, tree_callback);