2 Directory tree browser for the Midnight Commander
3 This module has been converted to be a widget.
5 The program load and saves the tree each time the tree widget is
6 created and destroyed. This is required for the future vfs layer,
7 it will be possible to have tree views over virtual file systems.
9 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
10 2003, 2004, 2005, 2007, 2011
11 The Free Software Foundation, Inc.
14 Janne Kukonlehto, 1994, 1996
16 Miguel de Icaza, 1996, 1999
18 This file is part of the Midnight Commander.
20 The Midnight Commander is free software: you can redistribute it
21 and/or modify it under the terms of the GNU General Public License as
22 published by the Free Software Foundation, either version 3 of the License,
23 or (at your option) any later version.
25 The Midnight Commander is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program. If not, see <http://www.gnu.org/licenses/>.
35 * \brief Source: directory tree browser
43 #include <sys/types.h>
45 #include "lib/global.h"
47 #include "lib/tty/tty.h"
48 #include "lib/tty/mouse.h"
49 #include "lib/tty/key.h"
51 #include "lib/vfs/vfs.h"
52 #include "lib/fileloc.h"
53 #include "lib/strutil.h"
55 #include "lib/widget.h"
56 #include "lib/event.h" /* mc_event_raise() */
58 #include "src/setup.h" /* confirm_delete, panels_options */
59 #include "src/keybind-defaults.h"
60 #include "src/history.h"
63 #include "midnight.h" /* the_menubar */
64 #include "file.h" /* copy_dir_dir(), move_dir_dir(), erase_dir() */
65 #include "layout.h" /* command_prompt */
66 #include "treestore.h"
72 /*** global variables ****************************************************************************/
74 /* The pointer to the tree */
75 WTree
*the_tree
= NULL
;
77 /* If this is true, then when browsing the tree the other window will
78 * automatically reload it's directory with the contents of the currently
83 /*** file scope macro definitions ****************************************************************/
85 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (panels_options.show_mini_info ? 2 : 0) : t->widget.lines)
87 /* Use the color of the parent widget for the unselected entries */
88 #define TREE_NORMALC(h) (h->color[DLG_COLOR_NORMAL])
89 #define TREE_CURRENTC(h) (h->color[DLG_COLOR_FOCUS])
91 /*** file scope type declarations ****************************************************************/
96 struct TreeStore
*store
;
97 tree_entry
*selected_ptr
; /* The selected directory */
98 char search_buffer
[MC_MAXFILENAMELEN
]; /* Current search string */
99 tree_entry
**tree_shown
; /* Entries currently on screen */
100 int is_panel
; /* panel or plain widget flag */
101 int active
; /* if it's currently selected */
102 int searching
; /* Are we on searching mode? */
103 int topdiff
; /* The difference between the topmost
104 shown and the selected */
107 /*** file scope variables ************************************************************************/
109 /* Specifies the display mode: 1d or 2d */
110 static gboolean tree_navigation_flag
= FALSE
;
112 /*** file scope functions ************************************************************************/
113 /* --------------------------------------------------------------------------------------------- */
115 static void tree_rescan (void *data
);
117 /* --------------------------------------------------------------------------------------------- */
120 back_ptr (tree_entry
* ptr
, int *count
)
124 while (ptr
&& ptr
->prev
&& i
< *count
)
133 /* --------------------------------------------------------------------------------------------- */
136 forw_ptr (tree_entry
* ptr
, int *count
)
140 while (ptr
&& ptr
->next
&& i
< *count
)
149 /* --------------------------------------------------------------------------------------------- */
152 remove_callback (tree_entry
* entry
, void *data
)
156 if (tree
->selected_ptr
== entry
)
158 if (tree
->selected_ptr
->next
)
159 tree
->selected_ptr
= tree
->selected_ptr
->next
;
161 tree
->selected_ptr
= tree
->selected_ptr
->prev
;
165 /* --------------------------------------------------------------------------------------------- */
166 /** Save the ${XDG_CACHE_HOME}/mc/Tree file */
169 save_tree (WTree
* tree
)
175 error
= tree_store_save ();
180 tree_name
= mc_config_get_full_path (MC_TREESTORE_FILE
);
181 fprintf (stderr
, _("Cannot open the %s file for writing:\n%s\n"), tree_name
,
182 unix_error_string (error
));
187 /* --------------------------------------------------------------------------------------------- */
190 tree_remove_entry (WTree
* tree
, const vfs_path_t
* name_vpath
)
193 tree_store_remove_entry (name_vpath
);
196 /* --------------------------------------------------------------------------------------------- */
199 tree_destroy (WTree
* tree
)
201 tree_store_remove_entry_remove_hook (remove_callback
);
204 g_free (tree
->tree_shown
);
205 tree
->tree_shown
= 0;
206 tree
->selected_ptr
= NULL
;
209 /* --------------------------------------------------------------------------------------------- */
210 /** Loads the .mc.tree file */
213 load_tree (WTree
* tree
)
217 tree
->selected_ptr
= tree
->store
->tree_first
;
218 tree_chdir (tree
, mc_config_get_home_dir ());
221 /* --------------------------------------------------------------------------------------------- */
224 tree_show_mini_info (WTree
* tree
, int tree_lines
, int tree_cols
)
226 Dlg_head
*h
= tree
->widget
.owner
;
232 if (!panels_options
.show_mini_info
)
234 line
= tree_lines
+ 2;
237 line
= tree_lines
+ 1;
241 /* Show search string */
242 tty_setcolor (INPUT_COLOR
);
243 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
244 widget_move (&tree
->widget
, line
, 1);
245 tty_print_char (PATH_SEP
);
246 tty_print_string (str_fit_to_term (tree
->search_buffer
, tree_cols
- 2, J_LEFT_FIT
));
247 tty_print_char (' ');
251 /* Show full name of selected directory */
254 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
255 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
256 widget_move (&tree
->widget
, line
, 1);
257 tmp_path
= vfs_path_to_str (tree
->selected_ptr
->name
);
258 tty_print_string (str_fit_to_term (tmp_path
, tree_cols
, J_LEFT_FIT
));
263 /* --------------------------------------------------------------------------------------------- */
266 show_tree (WTree
* tree
)
268 Dlg_head
*h
= tree
->widget
.owner
;
270 int i
, j
, topsublevel
;
272 int tree_lines
, tree_cols
;
275 tree_lines
= tlines (tree
);
276 tree_cols
= tree
->widget
.cols
;
278 widget_move ((Widget
*) tree
, y
, x
);
285 g_free (tree
->tree_shown
);
286 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
288 if (tree
->store
->tree_first
)
289 topsublevel
= tree
->store
->tree_first
->sublevel
;
292 if (!tree
->selected_ptr
)
294 tree
->selected_ptr
= tree
->store
->tree_first
;
297 current
= tree
->selected_ptr
;
299 /* Calculate the directory which is to be shown on the topmost line */
300 if (!tree_navigation_flag
)
301 current
= back_ptr (current
, &tree
->topdiff
);
305 while (current
->prev
&& i
< tree
->topdiff
)
309 current
= current
->prev
;
310 current_name
= vfs_path_to_str (current
->name
);
312 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
314 if (vfs_path_cmp (current
->name
, tree
->selected_ptr
->name
) == 0)
317 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
319 for (j
= strlen (current_name
) - 1; current_name
[j
] != PATH_SEP
; j
--);
320 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
325 if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
326 && vfs_path_len (tree
->selected_ptr
->name
) > 1)
328 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
,
329 vfs_path_len (tree
->selected_ptr
->name
)) == 0)
333 g_free (current_name
);
338 /* Loop for every line */
339 for (i
= 0; i
< tree_lines
; i
++)
341 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
343 /* Move to the beginning of the line */
344 tty_draw_hline (tree
->widget
.y
+ y
+ i
, tree
->widget
.x
+ x
, ' ', tree_cols
);
350 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
351 ? SELECTED_COLOR
: NORMAL_COLOR
);
353 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
355 tree
->tree_shown
[i
] = current
;
356 if (current
->sublevel
== topsublevel
)
361 current_name
= vfs_path_to_str (current
->name
);
362 tty_print_string (str_fit_to_term
363 (current_name
, tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
364 g_free (current_name
);
368 /* Sub level directory */
369 tty_set_alt_charset (TRUE
);
371 /* Output branch parts */
372 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
374 if (tree_cols
- 8 - 3 * j
< 9)
376 tty_print_char (' ');
377 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
378 tty_print_char (ACS_VLINE
);
380 tty_print_char (' ');
381 tty_print_char (' ');
383 tty_print_char (' ');
385 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
386 tty_print_char (ACS_LLCORNER
);
388 tty_print_char (ACS_LTEE
);
389 tty_print_char (ACS_HLINE
);
390 tty_set_alt_charset (FALSE
);
393 tty_print_char (' ');
394 tty_print_string (str_fit_to_term
395 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
398 /* Calculate the next value for current */
399 current
= current
->next
;
400 if (tree_navigation_flag
)
402 while (current
!= NULL
)
404 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
406 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
,
407 vfs_path_len (current
->name
)) == 0)
410 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
414 current_name
= vfs_path_to_str (current
->name
);
415 for (j
= strlen (current_name
) - 1; current_name
[j
] != PATH_SEP
; j
--)
417 g_free (current_name
);
418 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
421 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
422 && vfs_path_len (tree
->selected_ptr
->name
) > 1)
424 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
,
425 vfs_path_len (tree
->selected_ptr
->name
)) == 0)
428 current
= current
->next
;
433 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
436 /* --------------------------------------------------------------------------------------------- */
439 tree_check_focus (WTree
* tree
)
441 if (tree
->topdiff
< 3)
443 else if (tree
->topdiff
>= tlines (tree
) - 3)
444 tree
->topdiff
= tlines (tree
) - 3 - 1;
447 /* --------------------------------------------------------------------------------------------- */
450 tree_move_backward (WTree
* tree
, int i
)
452 if (!tree_navigation_flag
)
453 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
459 current
= tree
->selected_ptr
;
460 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
462 current
= current
->prev
;
463 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
465 tree
->selected_ptr
= current
;
473 tree_check_focus (tree
);
476 /* --------------------------------------------------------------------------------------------- */
479 tree_move_forward (WTree
* tree
, int i
)
481 if (!tree_navigation_flag
)
482 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
488 current
= tree
->selected_ptr
;
489 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
491 current
= current
->next
;
492 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
494 tree
->selected_ptr
= current
;
502 tree_check_focus (tree
);
505 /* --------------------------------------------------------------------------------------------- */
508 tree_move_to_child (WTree
* tree
)
512 /* Do we have a starting point? */
513 if (!tree
->selected_ptr
)
515 /* Take the next entry */
516 current
= tree
->selected_ptr
->next
;
517 /* Is it the child of the selected entry */
518 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
520 /* Yes -> select this entry */
521 tree
->selected_ptr
= current
;
523 tree_check_focus (tree
);
527 /* No -> rescan and try again */
529 current
= tree
->selected_ptr
->next
;
530 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
532 tree
->selected_ptr
= current
;
534 tree_check_focus (tree
);
539 /* --------------------------------------------------------------------------------------------- */
542 tree_move_to_parent (WTree
* tree
)
547 if (!tree
->selected_ptr
)
550 old
= tree
->selected_ptr
;
551 current
= tree
->selected_ptr
->prev
;
552 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
554 current
= current
->prev
;
558 current
= tree
->store
->tree_first
;
559 tree
->selected_ptr
= current
;
560 tree_check_focus (tree
);
561 return tree
->selected_ptr
!= old
;
564 /* --------------------------------------------------------------------------------------------- */
567 tree_move_to_top (WTree
* tree
)
569 tree
->selected_ptr
= tree
->store
->tree_first
;
573 /* --------------------------------------------------------------------------------------------- */
576 tree_move_to_bottom (WTree
* tree
)
578 tree
->selected_ptr
= tree
->store
->tree_last
;
579 tree
->topdiff
= tlines (tree
) - 3 - 1;
582 /* --------------------------------------------------------------------------------------------- */
583 /** Handle mouse click */
586 tree_event (WTree
* tree
, int y
)
588 if (tree
->tree_shown
[y
])
590 tree
->selected_ptr
= tree
->tree_shown
[y
];
596 /* --------------------------------------------------------------------------------------------- */
599 tree_chdir_sel (WTree
* tree
)
608 tmp_path
= vfs_path_to_str (tree
->selected_ptr
->name
);
609 if (do_cd (tmp_path
, cd_exact
))
610 select_item (current_panel
);
612 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
613 tmp_path
, unix_error_string (errno
));
620 /* --------------------------------------------------------------------------------------------- */
623 maybe_chdir (WTree
* tree
)
625 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
626 tree_chdir_sel (tree
);
629 /* --------------------------------------------------------------------------------------------- */
630 /** Mouse callback */
633 event_callback (Gpm_Event
* event
, void *data
)
637 /* rest of the upper frame, the menu is invisible - call menu */
638 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) && event
->y
== 1 && !menubar_visible
)
640 event
->x
+= tree
->widget
.x
;
641 return the_menubar
->widget
.mouse (event
, the_menubar
);
644 if (!(event
->type
& GPM_UP
))
657 tree_move_backward (tree
, tlines (tree
) - 1);
660 else if (event
->y
>= tlines (tree
))
662 tree_move_forward (tree
, tlines (tree
) - 1);
667 tree_event (tree
, event
->y
);
668 if ((event
->type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
670 tree_chdir_sel (tree
);
676 /* --------------------------------------------------------------------------------------------- */
677 /** Search tree for text */
680 search_tree (WTree
* tree
, char *text
)
688 current
= tree
->selected_ptr
;
690 while (!wrapped
|| current
!= tree
->selected_ptr
)
692 if (strncmp (current
->subname
, text
, len
) == 0)
694 tree
->selected_ptr
= current
;
698 current
= current
->next
;
701 current
= tree
->store
->tree_first
;
706 tree_check_focus (tree
);
710 /* --------------------------------------------------------------------------------------------- */
713 tree_do_search (WTree
* tree
, int key
)
717 l
= strlen (tree
->search_buffer
);
718 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
719 tree
->search_buffer
[--l
] = '\0';
720 else if (key
&& l
< sizeof (tree
->search_buffer
))
722 tree
->search_buffer
[l
] = key
;
723 tree
->search_buffer
[++l
] = '\0';
726 if (!search_tree (tree
, tree
->search_buffer
))
727 tree
->search_buffer
[--l
] = 0;
733 /* --------------------------------------------------------------------------------------------- */
736 tree_rescan (void *data
)
740 vfs_path_t
*old_vpath
;
742 old_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
743 if (old_vpath
== NULL
)
746 if (tree
->selected_ptr
!= NULL
&& mc_chdir (tree
->selected_ptr
->name
) == 0)
748 tree_store_rescan (tree
->selected_ptr
->name
);
749 ret
= mc_chdir (old_vpath
);
751 vfs_path_free (old_vpath
);
754 /* --------------------------------------------------------------------------------------------- */
757 tree_forget (void *data
)
760 if (tree
->selected_ptr
)
761 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
764 /* --------------------------------------------------------------------------------------------- */
767 tree_copy (WTree
* tree
, const char *default_dest
)
769 char msg
[BUF_MEDIUM
];
770 char *dest
, *selected_ptr_name
;
772 if (tree
->selected_ptr
== NULL
)
775 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
777 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
778 str_trunc (selected_ptr_name
, 50));
779 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
780 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
782 if (dest
!= NULL
&& *dest
!= '\0')
785 FileOpTotalContext
*tctx
;
787 ctx
= file_op_context_new (OP_COPY
);
788 tctx
= file_op_total_context_new ();
789 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
790 tctx
->ask_overwrite
= FALSE
;
791 copy_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
792 file_op_total_context_destroy (tctx
);
793 file_op_context_destroy (ctx
);
797 g_free (selected_ptr_name
);
800 /* --------------------------------------------------------------------------------------------- */
803 tree_move (WTree
* tree
, const char *default_dest
)
805 char msg
[BUF_MEDIUM
];
806 char *dest
, *selected_ptr_name
;
809 FileOpTotalContext
*tctx
;
811 if (tree
->selected_ptr
== NULL
)
814 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
816 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
817 str_trunc (selected_ptr_name
, 50));
819 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
821 if (dest
== NULL
|| *dest
== '\0')
824 if (stat (dest
, &buf
))
826 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
827 unix_error_string (errno
));
831 if (!S_ISDIR (buf
.st_mode
))
833 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
837 ctx
= file_op_context_new (OP_MOVE
);
838 tctx
= file_op_total_context_new ();
839 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
840 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
841 file_op_total_context_destroy (tctx
);
842 file_op_context_destroy (ctx
);
845 g_free (selected_ptr_name
);
849 /* --------------------------------------------------------------------------------------------- */
853 tree_mkdir (WTree
* tree
)
855 char old_dir
[MC_MAXPATHLEN
];
857 if (!tree
->selected_ptr
)
859 if (chdir (tree
->selected_ptr
->name
))
869 /* --------------------------------------------------------------------------------------------- */
872 tree_rmdir (void *data
)
876 FileOpTotalContext
*tctx
;
877 char *selected_ptr_name
;
879 if (!tree
->selected_ptr
)
882 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
889 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
890 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
894 g_free (selected_ptr_name
);
899 ctx
= file_op_context_new (OP_DELETE
);
900 tctx
= file_op_total_context_new ();
902 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
903 if (erase_dir (tctx
, ctx
, selected_ptr_name
) == FILE_CONT
)
905 file_op_total_context_destroy (tctx
);
906 file_op_context_destroy (ctx
);
907 g_free (selected_ptr_name
);
910 /* --------------------------------------------------------------------------------------------- */
913 tree_move_up (WTree
* tree
)
915 tree_move_backward (tree
, 1);
920 /* --------------------------------------------------------------------------------------------- */
923 tree_move_down (WTree
* tree
)
925 tree_move_forward (tree
, 1);
930 /* --------------------------------------------------------------------------------------------- */
933 tree_move_home (WTree
* tree
)
935 tree_move_to_top (tree
);
940 /* --------------------------------------------------------------------------------------------- */
943 tree_move_end (WTree
* tree
)
945 tree_move_to_bottom (tree
);
950 /* --------------------------------------------------------------------------------------------- */
953 tree_move_pgup (WTree
* tree
)
955 tree_move_backward (tree
, tlines (tree
) - 1);
960 /* --------------------------------------------------------------------------------------------- */
963 tree_move_pgdn (WTree
* tree
)
965 tree_move_forward (tree
, tlines (tree
) - 1);
970 /* --------------------------------------------------------------------------------------------- */
973 tree_move_left (WTree
* tree
)
977 if (tree_navigation_flag
)
979 v
= tree_move_to_parent (tree
);
987 /* --------------------------------------------------------------------------------------------- */
990 tree_move_right (WTree
* tree
)
994 if (tree_navigation_flag
)
996 tree_move_to_child (tree
);
1005 /* --------------------------------------------------------------------------------------------- */
1008 tree_start_search (WTree
* tree
)
1012 if (tree
->searching
)
1014 if (tree
->selected_ptr
== tree
->store
->tree_last
)
1015 tree_move_to_top (tree
);
1018 /* set navigation mode temporarily to 'Static' because in
1019 * dynamic navigation mode tree_move_forward will not move
1020 * to a lower sublevel if necessary (sequent searches must
1021 * start with the directory followed the last found directory)
1023 i
= tree_navigation_flag
;
1024 tree_navigation_flag
= 0;
1025 tree_move_forward (tree
, 1);
1026 tree_navigation_flag
= i
;
1028 tree_do_search (tree
, 0);
1032 tree
->searching
= 1;
1033 tree
->search_buffer
[0] = 0;
1037 /* --------------------------------------------------------------------------------------------- */
1040 tree_toggle_navig (WTree
* tree
)
1042 tree_navigation_flag
= !tree_navigation_flag
;
1043 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1044 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1045 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1048 /* --------------------------------------------------------------------------------------------- */
1051 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1053 cb_ret_t res
= MSG_HANDLED
;
1055 if (command
!= CK_Search
)
1056 tree
->searching
= 0;
1062 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1063 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1069 case CK_ToggleNavigation
:
1070 tree_toggle_navig (tree
);
1073 tree_copy (tree
, "");
1076 tree_move (tree
, "");
1079 tree_move_up (tree
);
1082 tree_move_down (tree
);
1085 tree_move_home (tree
);
1088 tree_move_end (tree
);
1091 tree_move_pgup (tree
);
1094 tree_move_pgdn (tree
);
1097 tree_chdir_sel (tree
);
1103 tree_start_search (tree
);
1109 /* don't close tree due to SIGINT */
1112 res
= MSG_NOT_HANDLED
;
1120 /* --------------------------------------------------------------------------------------------- */
1123 tree_key (WTree
* tree
, int key
)
1127 if (is_abort_char (key
))
1131 tree
->searching
= 0;
1133 return MSG_HANDLED
; /* eat abort char */
1135 /* modal tree dialog: let upper layer see the
1136 abort character and close the dialog */
1137 return MSG_NOT_HANDLED
;
1140 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1142 tree_do_search (tree
, key
);
1147 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1148 if (key
== tree_map
[i
].key
)
1149 switch (tree_map
[i
].command
)
1152 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1154 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1156 tree_execute_cmd (tree
, tree_map
[i
].command
);
1160 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1161 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1163 tree_start_search (tree
);
1164 tree_do_search (tree
, key
);
1168 return MSG_NOT_HANDLED
;
1171 /* --------------------------------------------------------------------------------------------- */
1174 tree_frame (Dlg_head
* h
, WTree
* tree
)
1176 tty_setcolor (NORMAL_COLOR
);
1177 widget_erase ((Widget
*) tree
);
1180 const char *title
= _("Directory tree");
1181 const int len
= str_term_width1 (title
);
1183 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1185 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1186 tty_printf (" %s ", title
);
1188 if (panels_options
.show_mini_info
)
1189 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1190 tty_print_alt_char (ACS_LTEE
, FALSE
);
1191 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1192 tty_print_alt_char (ACS_RTEE
, FALSE
);
1193 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1194 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1198 /* --------------------------------------------------------------------------------------------- */
1201 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1203 WTree
*tree
= (WTree
*) w
;
1204 Dlg_head
*h
= tree
->widget
.owner
;
1205 WButtonBar
*b
= find_buttonbar (h
);
1210 tree_frame (h
, tree
);
1216 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1217 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1218 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1219 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1220 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1221 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1222 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1224 /* FIXME: mkdir is currently defunct */
1225 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1227 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1229 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1230 buttonbar_redraw (b
);
1232 /* FIXME: Should find a better way of only displaying the
1233 currently selected item */
1237 /* FIXME: Should find a better way of changing the color of the
1240 case WIDGET_UNFOCUS
:
1242 tree
->searching
= 0;
1247 return tree_key (tree
, parm
);
1249 case WIDGET_COMMAND
:
1250 /* command from buttonbar */
1251 return tree_execute_cmd (tree
, parm
);
1253 case WIDGET_DESTROY
:
1254 tree_destroy (tree
);
1258 return default_proc (msg
, parm
);
1262 /* --------------------------------------------------------------------------------------------- */
1263 /*** public functions ****************************************************************************/
1264 /* --------------------------------------------------------------------------------------------- */
1267 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1269 WTree
*tree
= g_new (WTree
, 1);
1271 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1272 tree
->is_panel
= is_panel
;
1273 tree
->selected_ptr
= 0;
1275 tree
->store
= tree_store_get ();
1276 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1277 tree
->tree_shown
= 0;
1278 tree
->search_buffer
[0] = 0;
1279 tree
->topdiff
= tree
->widget
.lines
/ 2;
1280 tree
->searching
= 0;
1283 /* We do not want to keep the cursor */
1284 widget_want_cursor (tree
->widget
, 0);
1289 /* --------------------------------------------------------------------------------------------- */
1292 tree_chdir (WTree
* tree
, const char *dir
)
1295 tree_entry
*current
;
1297 vpath
= vfs_path_from_str (dir
);
1298 current
= tree_store_whereis (vpath
);
1299 if (current
!= NULL
)
1301 tree
->selected_ptr
= current
;
1302 tree_check_focus (tree
);
1304 vfs_path_free (vpath
);
1307 /* --------------------------------------------------------------------------------------------- */
1308 /** Return name of the currently selected entry */
1311 tree_selected_name (const WTree
* tree
)
1313 return tree
->selected_ptr
->name
;
1316 /* --------------------------------------------------------------------------------------------- */
1319 sync_tree (const char *path
)
1321 tree_chdir (the_tree
, path
);
1324 /* --------------------------------------------------------------------------------------------- */
1327 find_tree (struct Dlg_head
*h
)
1329 return (WTree
*) find_widget_type (h
, tree_callback
);
1332 /* --------------------------------------------------------------------------------------------- */