Change progressbar dialog.
[midnight-commander.git] / src / tree.c
blob109eeb1f5c3790ed29498db59a6045fc7dc348c1
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 {
82 Widget widget;
83 struct TreeStore *store;
84 tree_entry *selected_ptr; /* The selected directory */
85 char search_buffer[256]; /* 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){
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){
116 ptr = ptr->next;
117 i ++;
119 *count = i;
120 return ptr;
123 static void
124 remove_callback (tree_entry *entry, void *data)
126 WTree *tree = data;
128 if (tree->selected_ptr == entry){
129 if (tree->selected_ptr->next)
130 tree->selected_ptr = tree->selected_ptr->next;
131 else
132 tree->selected_ptr = tree->selected_ptr->prev;
136 /* Save the ~/.mc/Tree file */
137 static void
138 save_tree (WTree *tree)
140 int error;
141 char *tree_name;
143 (void) tree;
144 error = tree_store_save ();
147 if (error){
148 tree_name = g_build_filename (home_dir, MC_USERCONF_DIR,
149 MC_TREESTORE_FILE, (char *) NULL);
150 fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), tree_name,
151 unix_error_string (error));
152 g_free (tree_name);
156 static void
157 tree_remove_entry (WTree *tree, char *name)
159 (void) tree;
160 tree_store_remove_entry (name);
163 static void
164 tree_destroy (WTree *tree)
166 tree_store_remove_entry_remove_hook (remove_callback);
167 save_tree (tree);
169 g_free (tree->tree_shown);
170 tree->tree_shown = 0;
171 tree->selected_ptr = NULL;
174 /* Loads the .mc.tree file */
175 static void
176 load_tree (WTree *tree)
178 tree_store_load ();
180 tree->selected_ptr = tree->store->tree_first;
181 tree_chdir (tree, home_dir);
184 static void
185 tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
187 Dlg_head *h = tree->widget.parent;
188 int line;
190 /* Show mini info */
191 if (tree->is_panel){
192 if (!show_mini_info)
193 return;
194 line = tree_lines+2;
195 } else
196 line = tree_lines+1;
198 tty_draw_hline (tree->widget.y + line, tree->widget.x + 1, ' ', tree_cols);
199 widget_move (&tree->widget, line, 1);
201 if (tree->searching){
202 /* Show search string */
203 tty_setcolor (TREE_NORMALC (h));
204 tty_setcolor (DLG_FOCUSC (h));
205 tty_print_char (PATH_SEP);
207 tty_print_string (str_fit_to_term (tree->search_buffer,
208 tree_cols - 2, J_LEFT_FIT));
209 tty_print_char (' ');
210 tty_setcolor (DLG_FOCUSC (h));
211 } else {
212 /* Show full name of selected directory */
213 tty_print_string (str_fit_to_term (tree->selected_ptr->name,
214 tree_cols, J_LEFT_FIT));
218 static void
219 show_tree (WTree *tree)
221 Dlg_head *h = tree->widget.parent;
222 tree_entry *current;
223 int i, j, topsublevel;
224 int x, y;
225 int tree_lines, tree_cols;
227 /* Initialize */
228 x = y = 0;
229 tree_lines = tlines (tree);
230 tree_cols = tree->widget.cols;
232 tty_setcolor (TREE_NORMALC (h));
233 widget_move ((Widget*)tree, y, x);
234 if (tree->is_panel){
235 tree_cols -= 2;
236 x = y = 1;
239 g_free (tree->tree_shown);
240 tree->tree_shown = g_new0 (tree_entry *, tree_lines);
242 if (tree->store->tree_first)
243 topsublevel = tree->store->tree_first->sublevel;
244 else
245 topsublevel = 0;
246 if (!tree->selected_ptr){
247 tree->selected_ptr = tree->store->tree_first;
248 tree->topdiff = 0;
250 current = tree->selected_ptr;
252 /* Calculate the directory which is to be shown on the topmost line */
253 if (!tree_navigation_flag)
254 current = back_ptr (current, &tree->topdiff);
255 else {
256 i = 0;
257 while (current->prev && i < tree->topdiff){
258 current = current->prev;
259 if (current->sublevel < tree->selected_ptr->sublevel){
260 if (strncmp (current->name, tree->selected_ptr->name,
261 strlen (current->name)) == 0)
262 i++;
263 } else if (current->sublevel == tree->selected_ptr->sublevel){
264 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
265 if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
266 i++;
267 } else if (current->sublevel == tree->selected_ptr->sublevel + 1
268 && strlen (tree->selected_ptr->name) > 1){
269 if (strncmp (current->name, tree->selected_ptr->name,
270 strlen (tree->selected_ptr->name)) == 0)
271 i++;
274 tree->topdiff = i;
277 /* Loop for every line */
278 for (i = 0; i < tree_lines; i++){
279 /* Move to the beginning of the line */
280 tty_draw_hline (tree->widget.y + y + i, tree->widget.x + x, ' ', tree_cols);
282 if (!current)
283 continue;
285 tree->tree_shown [i] = current;
286 if (current->sublevel == topsublevel){
288 /* Top level directory */
289 if (tree->active && current == tree->selected_ptr) {
290 if (!tty_use_colors () && !tree->is_panel)
291 tty_setcolor (MARKED_COLOR);
292 else
293 tty_setcolor (SELECTED_COLOR);
296 /* Show full name */
297 tty_print_string (str_fit_to_term (current->name, tree_cols - 6, J_LEFT_FIT));
298 } else{
299 /* Sub level directory */
301 tty_set_alt_charset (TRUE);
302 /* Output branch parts */
303 for (j = 0; j < current->sublevel - topsublevel - 1; j++){
304 if (tree_cols - 8 - 3 * j < 9)
305 break;
306 tty_print_char (' ');
307 if (current->submask & (1 << (j + topsublevel + 1)))
308 tty_print_char (ACS_VLINE);
309 else
310 tty_print_char (' ');
311 tty_print_char (' ');
313 tty_print_char (' '); j++;
314 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
315 tty_print_char (ACS_LLCORNER);
316 else
317 tty_print_char (ACS_LTEE);
318 tty_print_char (ACS_HLINE);
319 tty_set_alt_charset (FALSE);
321 if (tree->active && current == tree->selected_ptr) {
322 /* Selected directory -> change color */
323 if (!tty_use_colors () && !tree->is_panel)
324 tty_setcolor (MARKED_COLOR);
325 else
326 tty_setcolor (SELECTED_COLOR);
329 /* Show sub-name */
330 tty_print_char (' ');
331 tty_print_string (str_fit_to_term (current->subname,
332 tree_cols - 2 - 4 - 3 * j, J_LEFT_FIT));
334 tty_print_char (' ');
336 /* Return to normal color */
337 tty_setcolor (TREE_NORMALC (h));
339 /* Calculate the next value for current */
340 current = current->next;
341 if (tree_navigation_flag){
342 while (current){
343 if (current->sublevel < tree->selected_ptr->sublevel){
344 if (strncmp (current->name, tree->selected_ptr->name,
345 strlen (current->name)) == 0)
346 break;
347 } else if (current->sublevel == tree->selected_ptr->sublevel){
348 for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
349 if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
350 break;
351 } else if (current->sublevel == tree->selected_ptr->sublevel+1
352 && strlen (tree->selected_ptr->name) > 1){
353 if (strncmp (current->name, tree->selected_ptr->name,
354 strlen (tree->selected_ptr->name)) == 0)
355 break;
357 current = current->next;
361 tree_show_mini_info (tree, tree_lines, tree_cols);
364 static void
365 tree_check_focus (WTree *tree)
367 if (tree->topdiff < 3)
368 tree->topdiff = 3;
369 else if (tree->topdiff >= tlines (tree) - 3)
370 tree->topdiff = tlines (tree) - 3 - 1;
373 static void
374 tree_move_backward (WTree *tree, int i)
376 if (!tree_navigation_flag)
377 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
378 else {
379 tree_entry *current;
380 int j = 0;
382 current = tree->selected_ptr;
383 while (j < i && current->prev
384 && current->prev->sublevel >= tree->selected_ptr->sublevel){
385 current = current->prev;
386 if (current->sublevel == tree->selected_ptr->sublevel){
387 tree->selected_ptr = current;
388 j++;
391 i = j;
394 tree->topdiff -= i;
395 tree_check_focus (tree);
398 static void
399 tree_move_forward (WTree *tree, int i)
401 if (!tree_navigation_flag)
402 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
403 else {
404 tree_entry *current;
405 int j = 0;
407 current = tree->selected_ptr;
408 while (j < i && current->next
409 && current->next->sublevel >= tree->selected_ptr->sublevel){
410 current = current->next;
411 if (current->sublevel == tree->selected_ptr->sublevel){
412 tree->selected_ptr = current;
413 j ++;
416 i = j;
419 tree->topdiff += i;
420 tree_check_focus (tree);
423 static void
424 tree_move_to_child (WTree *tree)
426 tree_entry *current;
428 /* Do we have a starting point? */
429 if (!tree->selected_ptr)
430 return;
431 /* Take the next entry */
432 current = tree->selected_ptr->next;
433 /* Is it the child of the selected entry */
434 if (current && current->sublevel > tree->selected_ptr->sublevel){
435 /* Yes -> select this entry */
436 tree->selected_ptr = current;
437 tree->topdiff++;
438 tree_check_focus (tree);
439 } else {
440 /* No -> rescan and try again */
441 tree_rescan (tree);
442 current = tree->selected_ptr->next;
443 if (current && current->sublevel > tree->selected_ptr->sublevel){
444 tree->selected_ptr = current;
445 tree->topdiff++;
446 tree_check_focus (tree);
451 static gboolean
452 tree_move_to_parent (WTree *tree)
454 tree_entry *current;
455 tree_entry *old;
457 if (!tree->selected_ptr)
458 return FALSE;
460 old = tree->selected_ptr;
461 current = tree->selected_ptr->prev;
462 while (current && current->sublevel >= tree->selected_ptr->sublevel){
463 current = current->prev;
464 tree->topdiff--;
466 if (!current)
467 current = tree->store->tree_first;
468 tree->selected_ptr = current;
469 tree_check_focus (tree);
470 return tree->selected_ptr != old;
473 static void
474 tree_move_to_top (WTree *tree)
476 tree->selected_ptr = tree->store->tree_first;
477 tree->topdiff = 0;
480 static void
481 tree_move_to_bottom (WTree *tree)
483 tree->selected_ptr = tree->store->tree_last;
484 tree->topdiff = tlines (tree) - 3 - 1;
487 /* Handle mouse click */
488 static void
489 tree_event (WTree *tree, int y)
491 if (tree->tree_shown [y]){
492 tree->selected_ptr = tree->tree_shown [y];
493 tree->topdiff = y;
495 show_tree (tree);
498 static void
499 tree_chdir_sel (WTree *tree)
501 if (!tree->is_panel)
502 return;
504 change_panel ();
506 if (do_cd (tree->selected_ptr->name, cd_exact))
507 select_item (current_panel);
508 else
509 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
510 tree->selected_ptr->name, unix_error_string (errno));
512 change_panel ();
513 show_tree (tree);
516 static void
517 maybe_chdir (WTree *tree)
519 if (xtree_mode && tree->is_panel && is_idle ())
520 tree_chdir_sel (tree);
523 /* Mouse callback */
524 static int
525 event_callback (Gpm_Event *event, void *data)
527 WTree *tree = data;
529 /* rest of the upper frame, the menu is invisible - call menu */
530 if (tree->is_panel && (event->type & GPM_DOWN)
531 && event->y == 1 && !menubar_visible) {
532 event->x += tree->widget.x;
533 return the_menubar->widget.mouse (event, the_menubar);
536 if (!(event->type & GPM_UP))
537 return MOU_NORMAL;
539 if (tree->is_panel)
540 event->y--;
542 event->y--;
544 if (!tree->active)
545 change_panel ();
547 if (event->y < 0){
548 tree_move_backward (tree, tlines (tree) - 1);
549 show_tree (tree);
550 } else if (event->y >= tlines (tree)){
551 tree_move_forward (tree, tlines (tree) - 1);
552 show_tree (tree);
553 } else {
554 tree_event (tree, event->y);
555 if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
556 tree_chdir_sel (tree);
559 return MOU_NORMAL;
562 /* Search tree for text */
563 static int
564 search_tree (WTree *tree, char *text)
566 tree_entry *current;
567 int len;
568 int wrapped = 0;
569 int found = 0;
571 len = strlen (text);
572 current = tree->selected_ptr;
573 found = 0;
574 while (!wrapped || current != tree->selected_ptr){
575 if (strncmp (current->subname, text, len) == 0){
576 tree->selected_ptr = current;
577 found = 1;
578 break;
580 current = current->next;
581 if (!current){
582 current = tree->store->tree_first;
583 wrapped = 1;
585 tree->topdiff++;
587 tree_check_focus (tree);
588 return found;
591 static void
592 tree_do_search (WTree *tree, int key)
594 size_t l;
596 l = strlen (tree->search_buffer);
597 if ((l != 0) && (key == KEY_BACKSPACE))
598 tree->search_buffer [--l] = '\0';
599 else if (key && l < sizeof (tree->search_buffer)){
600 tree->search_buffer [l] = key;
601 tree->search_buffer [++l] = '\0';
604 if (!search_tree (tree, tree->search_buffer))
605 tree->search_buffer [--l] = 0;
607 show_tree (tree);
608 maybe_chdir (tree);
611 static void
612 tree_rescan (void *data)
614 char old_dir [MC_MAXPATHLEN];
615 WTree *tree = data;
617 if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
618 mc_chdir (tree->selected_ptr->name))
619 return;
621 tree_store_rescan (tree->selected_ptr->name);
622 mc_chdir (old_dir);
625 static void
626 tree_forget (void *data)
628 WTree *tree = data;
629 if (tree->selected_ptr)
630 tree_remove_entry (tree, tree->selected_ptr->name);
633 static void
634 tree_copy (WTree *tree, const char *default_dest)
636 char msg [BUF_MEDIUM];
637 char *dest;
639 if (tree->selected_ptr == NULL)
640 return;
642 g_snprintf (msg, sizeof (msg), _("Copy \"%s\" directory to:"),
643 str_trunc (tree->selected_ptr->name, 50));
644 dest = input_expand_dialog (Q_("DialogTitle|Copy"),
645 msg, MC_HISTORY_FM_TREE_COPY, default_dest);
647 if (dest != NULL && *dest != '\0') {
648 FileOpContext *ctx;
649 FileOpTotalContext *tctx;
651 ctx = file_op_context_new (OP_COPY);
652 tctx = file_op_total_context_new ();
653 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_MULTI_ITEM);
654 tctx->ask_overwrite = FALSE;
655 tctx->is_toplevel_file = FALSE;
656 copy_dir_dir (tctx, ctx, tree->selected_ptr->name, dest, TRUE, FALSE, FALSE, NULL);
657 file_op_total_context_destroy (tctx);
658 file_op_context_destroy (ctx);
661 g_free (dest);
664 static void
665 tree_move (WTree *tree, const char *default_dest)
667 char msg [BUF_MEDIUM];
668 char *dest;
669 struct stat buf;
670 FileOpContext *ctx;
671 FileOpTotalContext *tctx;
673 if (tree->selected_ptr == NULL)
674 return;
676 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
677 str_trunc (tree->selected_ptr->name, 50));
678 dest = input_expand_dialog (Q_("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
680 if (dest == NULL || *dest == '\0') {
681 g_free (dest);
682 return;
685 if (stat (dest, &buf)){
686 message (D_ERROR, MSG_ERROR, _(" Cannot stat the destination \n %s "),
687 unix_error_string (errno));
688 g_free (dest);
689 return;
692 if (!S_ISDIR (buf.st_mode)){
693 file_error (_(" Destination \"%s\" must be a directory \n %s "),
694 dest);
695 g_free (dest);
696 return;
699 ctx = file_op_context_new (OP_MOVE);
700 tctx = file_op_total_context_new ();
701 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
702 move_dir_dir (tctx, ctx, tree->selected_ptr->name, dest);
703 file_op_total_context_destroy (tctx);
704 file_op_context_destroy (ctx);
706 g_free (dest);
709 #if 0
710 static void
711 tree_mkdir (WTree *tree)
713 char old_dir [MC_MAXPATHLEN];
715 if (!tree->selected_ptr)
716 return;
717 if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
718 return;
719 if (chdir (tree->selected_ptr->name))
720 return;
721 /* FIXME
722 mkdir_cmd (tree);
724 tree_rescan (tree);
725 chdir (old_dir);
727 #endif
729 static void
730 tree_rmdir (void *data)
732 WTree *tree = data;
733 FileOpContext *ctx;
734 FileOpTotalContext *tctx;
736 if (!tree->selected_ptr)
737 return;
739 if (confirm_delete) {
740 char *buf;
741 int result;
743 buf =
744 g_strdup_printf (_(" Delete %s? "),
745 tree->selected_ptr->name);
746 result =
747 query_dialog (Q_("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
748 g_free (buf);
749 if (result != 0)
750 return;
753 ctx = file_op_context_new (OP_DELETE);
754 tctx = file_op_total_context_new ();
756 file_op_context_create_ui (ctx, FALSE, FILEGUI_DIALOG_ONE_ITEM);
757 if (erase_dir (tctx, ctx, tree->selected_ptr->name) == FILE_CONT)
758 tree_forget (tree);
759 file_op_total_context_destroy (tctx);
760 file_op_context_destroy (ctx);
763 static inline void
764 tree_move_up (WTree *tree)
766 tree_move_backward (tree, 1);
767 show_tree (tree);
768 maybe_chdir (tree);
771 static inline void
772 tree_move_down (WTree *tree)
774 tree_move_forward (tree, 1);
775 show_tree (tree);
776 maybe_chdir (tree);
779 static inline void
780 tree_move_home (WTree *tree)
782 tree_move_to_top (tree);
783 show_tree (tree);
784 maybe_chdir (tree);
787 static inline void
788 tree_move_end (WTree *tree)
790 tree_move_to_bottom (tree);
791 show_tree (tree);
792 maybe_chdir (tree);
795 static void
796 tree_move_pgup (WTree *tree)
798 tree_move_backward (tree, tlines (tree) - 1);
799 show_tree (tree);
800 maybe_chdir (tree);
803 static void
804 tree_move_pgdn (WTree *tree)
806 tree_move_forward (tree, tlines (tree) - 1);
807 show_tree (tree);
808 maybe_chdir (tree);
811 static gboolean
812 tree_move_left (WTree *tree)
814 gboolean v = FALSE;
816 if (tree_navigation_flag) {
817 v = tree_move_to_parent (tree);
818 show_tree (tree);
819 maybe_chdir (tree);
822 return v;
825 static gboolean
826 tree_move_right (WTree *tree)
828 gboolean v = FALSE;
830 if (tree_navigation_flag) {
831 tree_move_to_child (tree);
832 show_tree (tree);
833 maybe_chdir (tree);
834 v = TRUE;
837 return v;
840 static void
841 tree_start_search (WTree *tree)
843 gboolean i;
845 if (tree->searching) {
846 if (tree->selected_ptr == tree->store->tree_last)
847 tree_move_to_top (tree);
848 else {
849 /* set navigation mode temporarily to 'Static' because in
850 * dynamic navigation mode tree_move_forward will not move
851 * to a lower sublevel if necessary (sequent searches must
852 * start with the directory followed the last found directory)
854 i = tree_navigation_flag;
855 tree_navigation_flag = 0;
856 tree_move_forward (tree, 1);
857 tree_navigation_flag = i;
859 tree_do_search (tree, 0);
860 } else {
861 tree->searching = 1;
862 tree->search_buffer[0] = 0;
866 static void
867 tree_toggle_navig (WTree *tree)
869 tree_navigation_flag = !tree_navigation_flag;
870 buttonbar_set_label (find_buttonbar (tree->widget.parent), 4,
871 tree_navigation_flag ? Q_("ButtonBar|Static")
872 : Q_("ButtonBar|Dynamc"),
873 tree_map, (Widget *) tree);
876 static cb_ret_t
877 tree_execute_cmd (WTree *tree, unsigned long command)
879 cb_ret_t res = MSG_HANDLED;
881 if (command != CK_TreeStartSearch)
882 tree->searching = 0;
884 switch (command) {
885 case CK_TreeHelp:
886 interactive_display (NULL, "[Directory Tree]");
887 break;
888 case CK_TreeForget:
889 tree_forget (tree);
890 break;
891 case CK_TreeToggleNav:
892 tree_toggle_navig (tree);
893 break;
894 case CK_TreeCopy:
895 tree_copy (tree, "");
896 break;
897 case CK_TreeMove:
898 tree_move (tree, "");
899 break;
900 case CK_TreeMoveUp:
901 tree_move_up (tree);
902 break;
903 case CK_TreeMoveDown:
904 tree_move_down (tree);
905 break;
906 case CK_TreeMoveHome:
907 tree_move_home (tree);
908 break;
909 case CK_TreeMoveEnd:
910 tree_move_end (tree);
911 break;
912 case CK_TreeMovePgUp:
913 tree_move_pgup (tree);
914 break;
915 case CK_TreeMovePgDn:
916 tree_move_pgdn (tree);
917 break;
918 case CK_TreeOpen:
919 tree_chdir_sel (tree);
920 break;
921 case CK_TreeRescan:
922 tree_rescan (tree);
923 break;
924 case CK_TreeStartSearch:
925 tree_start_search (tree);
926 break;
927 case CK_TreeRemove:
928 tree_rmdir (tree);
929 break;
930 default:
931 res = MSG_NOT_HANDLED;
934 show_tree (tree);
936 return res;
939 static cb_ret_t
940 tree_key (WTree *tree, int key)
942 size_t i;
944 for (i = 0; tree_map [i].key != 0; i++)
945 if (key == tree_map [i].key)
946 switch (tree_map [i].command) {
947 case CK_TreeMoveLeft:
948 return tree_move_left (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
949 case CK_TreeMoveRight:
950 return tree_move_right (tree) ? MSG_HANDLED : MSG_NOT_HANDLED;
951 default:
952 tree_execute_cmd (tree, tree_map [i].command);
953 return MSG_HANDLED;
956 if (is_abort_char (key)) {
957 if (tree->is_panel) {
958 tree->searching = 0;
959 show_tree (tree);
960 return MSG_HANDLED; /* eat abort char */
962 /* modal tree dialog: let upper layer see the
963 abort character and close the dialog */
964 return MSG_NOT_HANDLED;
967 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
968 if ((key >= ' ' && key <= 255) || key == KEY_BACKSPACE) {
969 if (tree->searching){
970 tree_do_search (tree, key);
971 show_tree (tree);
972 return MSG_HANDLED;
975 if (!command_prompt) {
976 tree_start_search (tree);
977 tree_do_search (tree, key);
978 return MSG_HANDLED;
980 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
983 return MSG_NOT_HANDLED;
986 static void
987 tree_frame (Dlg_head *h, WTree *tree)
989 tty_setcolor (NORMAL_COLOR);
990 widget_erase ((Widget*) tree);
991 if (tree->is_panel) {
992 draw_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
993 tree->widget.cols);
995 if (show_mini_info)
996 tty_draw_hline (tree->widget.y + tlines (tree) + 1,
997 tree->widget.x + 1,
998 ACS_HLINE, tree->widget.cols - 2);
1002 static cb_ret_t
1003 tree_callback (Widget *w, widget_msg_t msg, int parm)
1005 WTree *tree = (WTree *) w;
1006 Dlg_head *h = tree->widget.parent;
1007 WButtonBar *b = find_buttonbar (h);
1009 switch (msg) {
1010 case WIDGET_DRAW:
1011 tree_frame (h, tree);
1012 show_tree (tree);
1013 return MSG_HANDLED;
1015 case WIDGET_FOCUS:
1016 tree->active = 1;
1017 buttonbar_set_label (b, 1, Q_("ButtonBar|Help"), tree_map, (Widget *) tree);
1018 buttonbar_set_label (b, 2, Q_("ButtonBar|Rescan"), tree_map, (Widget *) tree);
1019 buttonbar_set_label (b, 3, Q_("ButtonBar|Forget"), tree_map, (Widget *) tree);
1020 buttonbar_set_label (b, 4, tree_navigation_flag ? Q_("ButtonBar|Static")
1021 : Q_("ButtonBar|Dynamc"),
1022 tree_map, (Widget *) tree);
1023 buttonbar_set_label (b, 5, Q_("ButtonBar|Copy"), tree_map, (Widget *) tree);
1024 buttonbar_set_label (b, 6, Q_("ButtonBar|RenMov"), tree_map, (Widget *) tree);
1025 #if 0
1026 /* FIXME: mkdir is currently defunct */
1027 buttonbar_set_label (b, 7, Q_("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1028 #else
1029 buttonbar_clear_label (b, 7, (Widget *) tree);
1030 #endif
1031 buttonbar_set_label (b, 8, Q_("ButtonBar|Rmdir"), tree_map, (Widget *) tree);
1032 buttonbar_redraw (b);
1034 /* FIXME: Should find a better way of only displaying the
1035 currently selected item */
1036 show_tree (tree);
1037 return MSG_HANDLED;
1039 /* FIXME: Should find a better way of changing the color of the
1040 selected item */
1042 case WIDGET_UNFOCUS:
1043 tree->active = 0;
1044 show_tree (tree);
1045 return MSG_HANDLED;
1047 case WIDGET_KEY:
1048 return tree_key (tree, parm);
1050 case WIDGET_COMMAND:
1051 /* command from buttonbar */
1052 return tree_execute_cmd (tree, parm);
1054 case WIDGET_DESTROY:
1055 tree_destroy (tree);
1056 return MSG_HANDLED;
1058 default:
1059 return default_proc (msg, parm);
1063 WTree *
1064 tree_new (int is_panel, int y, int x, int lines, int cols)
1066 WTree *tree = g_new (WTree, 1);
1068 init_widget (&tree->widget, y, x, lines, cols,
1069 tree_callback, event_callback);
1070 tree->is_panel = is_panel;
1071 tree->selected_ptr = 0;
1073 tree->store = tree_store_get ();
1074 tree_store_add_entry_remove_hook (remove_callback, tree);
1075 tree->tree_shown = 0;
1076 tree->search_buffer[0] = 0;
1077 tree->topdiff = tree->widget.lines / 2;
1078 tree->searching = 0;
1079 tree->active = 0;
1081 /* We do not want to keep the cursor */
1082 widget_want_cursor (tree->widget, 0);
1083 load_tree (tree);
1084 return tree;
1087 void
1088 tree_chdir (WTree *tree, const char *dir)
1090 tree_entry *current;
1092 current = tree_store_whereis (dir);
1094 if (current != NULL) {
1095 tree->selected_ptr = current;
1096 tree_check_focus (tree);
1100 /* Return name of the currently selected entry */
1101 char *
1102 tree_selected_name (const WTree *tree)
1104 return tree->selected_ptr->name;
1107 void
1108 sync_tree (const char *path)
1110 tree_chdir (the_tree, path);
1113 WTree *
1114 find_tree (struct Dlg_head *h)
1116 return (WTree *) find_widget_type (h, tree_callback);