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 /* --------------------------------------------------------------------------------------------- */
584 /** Handle mouse click */
586 tree_mouse_click (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 (tree
->selected_ptr
->name
, 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 tree_event (Gpm_Event
* event
, void *data
)
635 WTree
*tree
= (WTree
*) data
;
636 Widget
*w
= (Widget
*) data
;
639 if (!mouse_global_in_widget (event
, w
))
640 return MOU_UNHANDLED
;
642 local
= mouse_get_local (event
, w
);
644 /* rest of the upper frame, the menu is invisible - call menu */
645 if (tree
->is_panel
&& (local
.type
& GPM_DOWN
) != 0 && local
.y
== 1 && !menubar_visible
)
646 return the_menubar
->widget
.mouse (event
, the_menubar
);
648 if ((local
.type
& GPM_UP
) == 0)
661 tree_move_backward (tree
, tlines (tree
) - 1);
664 else if (local
.y
>= tlines (tree
))
666 tree_move_forward (tree
, tlines (tree
) - 1);
671 tree_mouse_click (tree
, local
.y
);
672 if ((local
.type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
673 tree_chdir_sel (tree
);
679 /* --------------------------------------------------------------------------------------------- */
680 /** Search tree for text */
683 search_tree (WTree
* tree
, char *text
)
691 current
= tree
->selected_ptr
;
693 while (!wrapped
|| current
!= tree
->selected_ptr
)
695 if (strncmp (current
->subname
, text
, len
) == 0)
697 tree
->selected_ptr
= current
;
701 current
= current
->next
;
704 current
= tree
->store
->tree_first
;
709 tree_check_focus (tree
);
713 /* --------------------------------------------------------------------------------------------- */
716 tree_do_search (WTree
* tree
, int key
)
720 l
= strlen (tree
->search_buffer
);
721 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
722 tree
->search_buffer
[--l
] = '\0';
723 else if (key
&& l
< sizeof (tree
->search_buffer
))
725 tree
->search_buffer
[l
] = key
;
726 tree
->search_buffer
[++l
] = '\0';
729 if (!search_tree (tree
, tree
->search_buffer
))
730 tree
->search_buffer
[--l
] = 0;
736 /* --------------------------------------------------------------------------------------------- */
739 tree_rescan (void *data
)
743 vfs_path_t
*old_vpath
;
745 old_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
746 if (old_vpath
== NULL
)
749 if (tree
->selected_ptr
!= NULL
&& mc_chdir (tree
->selected_ptr
->name
) == 0)
751 tree_store_rescan (tree
->selected_ptr
->name
);
752 ret
= mc_chdir (old_vpath
);
754 vfs_path_free (old_vpath
);
757 /* --------------------------------------------------------------------------------------------- */
760 tree_forget (void *data
)
763 if (tree
->selected_ptr
)
764 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
767 /* --------------------------------------------------------------------------------------------- */
770 tree_copy (WTree
* tree
, const char *default_dest
)
772 char msg
[BUF_MEDIUM
];
773 char *dest
, *selected_ptr_name
;
775 if (tree
->selected_ptr
== NULL
)
778 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
780 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
781 str_trunc (selected_ptr_name
, 50));
782 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
783 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
785 if (dest
!= NULL
&& *dest
!= '\0')
788 FileOpTotalContext
*tctx
;
790 ctx
= file_op_context_new (OP_COPY
);
791 tctx
= file_op_total_context_new ();
792 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
793 tctx
->ask_overwrite
= FALSE
;
794 copy_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
795 file_op_total_context_destroy (tctx
);
796 file_op_context_destroy (ctx
);
800 g_free (selected_ptr_name
);
803 /* --------------------------------------------------------------------------------------------- */
806 tree_move (WTree
* tree
, const char *default_dest
)
808 char msg
[BUF_MEDIUM
];
809 char *dest
, *selected_ptr_name
;
812 FileOpTotalContext
*tctx
;
814 if (tree
->selected_ptr
== NULL
)
817 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
819 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
820 str_trunc (selected_ptr_name
, 50));
822 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
824 if (dest
== NULL
|| *dest
== '\0')
827 if (stat (dest
, &buf
))
829 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
830 unix_error_string (errno
));
834 if (!S_ISDIR (buf
.st_mode
))
836 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
840 ctx
= file_op_context_new (OP_MOVE
);
841 tctx
= file_op_total_context_new ();
842 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
843 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
844 file_op_total_context_destroy (tctx
);
845 file_op_context_destroy (ctx
);
848 g_free (selected_ptr_name
);
852 /* --------------------------------------------------------------------------------------------- */
856 tree_mkdir (WTree
* tree
)
858 char old_dir
[MC_MAXPATHLEN
];
860 if (!tree
->selected_ptr
)
862 if (chdir (tree
->selected_ptr
->name
))
872 /* --------------------------------------------------------------------------------------------- */
875 tree_rmdir (void *data
)
879 FileOpTotalContext
*tctx
;
881 if (!tree
->selected_ptr
)
888 char *selected_ptr_name
;
890 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
891 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
892 g_free (selected_ptr_name
);
894 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
900 ctx
= file_op_context_new (OP_DELETE
);
901 tctx
= file_op_total_context_new ();
903 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
904 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
906 file_op_total_context_destroy (tctx
);
907 file_op_context_destroy (ctx
);
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 if (!tree
->is_panel
)
1110 dlg_stop (((Widget
*) tree
)->owner
);
1113 res
= MSG_NOT_HANDLED
;
1121 /* --------------------------------------------------------------------------------------------- */
1124 tree_key (WTree
* tree
, int key
)
1128 if (is_abort_char (key
))
1132 tree
->searching
= 0;
1134 return MSG_HANDLED
; /* eat abort char */
1136 /* modal tree dialog: let upper layer see the
1137 abort character and close the dialog */
1138 return MSG_NOT_HANDLED
;
1141 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1143 tree_do_search (tree
, key
);
1148 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1149 if (key
== tree_map
[i
].key
)
1150 switch (tree_map
[i
].command
)
1153 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1155 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1157 tree_execute_cmd (tree
, tree_map
[i
].command
);
1161 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1162 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1164 tree_start_search (tree
);
1165 tree_do_search (tree
, key
);
1169 return MSG_NOT_HANDLED
;
1172 /* --------------------------------------------------------------------------------------------- */
1175 tree_frame (Dlg_head
* h
, WTree
* tree
)
1177 tty_setcolor (NORMAL_COLOR
);
1178 widget_erase ((Widget
*) tree
);
1181 const char *title
= _("Directory tree");
1182 const int len
= str_term_width1 (title
);
1184 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1186 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1187 tty_printf (" %s ", title
);
1189 if (panels_options
.show_mini_info
)
1190 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1191 tty_print_alt_char (ACS_LTEE
, FALSE
);
1192 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1193 tty_print_alt_char (ACS_RTEE
, FALSE
);
1194 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1195 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1199 /* --------------------------------------------------------------------------------------------- */
1202 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1204 WTree
*tree
= (WTree
*) w
;
1205 Dlg_head
*h
= tree
->widget
.owner
;
1206 WButtonBar
*b
= find_buttonbar (h
);
1211 tree_frame (h
, tree
);
1217 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1218 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1219 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1220 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1221 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1222 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1223 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1225 /* FIXME: mkdir is currently defunct */
1226 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1228 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1230 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1231 buttonbar_redraw (b
);
1233 /* FIXME: Should find a better way of only displaying the
1234 currently selected item */
1238 /* FIXME: Should find a better way of changing the color of the
1241 case WIDGET_UNFOCUS
:
1243 tree
->searching
= 0;
1248 return tree_key (tree
, parm
);
1250 case WIDGET_COMMAND
:
1251 /* command from buttonbar */
1252 return tree_execute_cmd (tree
, parm
);
1254 case WIDGET_DESTROY
:
1255 tree_destroy (tree
);
1259 return default_proc (msg
, parm
);
1263 /* --------------------------------------------------------------------------------------------- */
1264 /*** public functions ****************************************************************************/
1265 /* --------------------------------------------------------------------------------------------- */
1268 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1270 WTree
*tree
= g_new (WTree
, 1);
1272 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, tree_event
);
1273 tree
->is_panel
= is_panel
;
1274 tree
->selected_ptr
= 0;
1276 tree
->store
= tree_store_get ();
1277 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1278 tree
->tree_shown
= 0;
1279 tree
->search_buffer
[0] = 0;
1280 tree
->topdiff
= tree
->widget
.lines
/ 2;
1281 tree
->searching
= 0;
1284 /* We do not want to keep the cursor */
1285 widget_want_cursor (tree
->widget
, 0);
1290 /* --------------------------------------------------------------------------------------------- */
1293 tree_chdir (WTree
* tree
, const char *dir
)
1296 tree_entry
*current
;
1298 vpath
= vfs_path_from_str (dir
);
1299 current
= tree_store_whereis (vpath
);
1300 if (current
!= NULL
)
1302 tree
->selected_ptr
= current
;
1303 tree_check_focus (tree
);
1305 vfs_path_free (vpath
);
1308 /* --------------------------------------------------------------------------------------------- */
1309 /** Return name of the currently selected entry */
1312 tree_selected_name (const WTree
* tree
)
1314 return tree
->selected_ptr
->name
;
1317 /* --------------------------------------------------------------------------------------------- */
1320 sync_tree (const char *path
)
1322 tree_chdir (the_tree
, path
);
1325 /* --------------------------------------------------------------------------------------------- */
1328 find_tree (struct Dlg_head
*h
)
1330 return (WTree
*) find_widget_type (h
, tree_callback
);
1333 /* --------------------------------------------------------------------------------------------- */