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 /* rest of the upper frame - call menu */
643 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) != 0 && event
->y
== w
->owner
->y
+ 1)
644 return MOU_UNHANDLED
;
646 local
= mouse_get_local (event
, w
);
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
)
742 vfs_path_t
*old_vpath
;
744 old_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
745 if (old_vpath
== NULL
)
748 if (tree
->selected_ptr
!= NULL
&& mc_chdir (tree
->selected_ptr
->name
) == 0)
750 tree_store_rescan (tree
->selected_ptr
->name
);
751 mc_chdir (old_vpath
);
753 vfs_path_free (old_vpath
);
756 /* --------------------------------------------------------------------------------------------- */
759 tree_forget (void *data
)
762 if (tree
->selected_ptr
)
763 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
766 /* --------------------------------------------------------------------------------------------- */
769 tree_copy (WTree
* tree
, const char *default_dest
)
771 char msg
[BUF_MEDIUM
];
772 char *dest
, *selected_ptr_name
;
774 if (tree
->selected_ptr
== NULL
)
777 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
779 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
780 str_trunc (selected_ptr_name
, 50));
781 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
782 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
784 if (dest
!= NULL
&& *dest
!= '\0')
787 FileOpTotalContext
*tctx
;
789 ctx
= file_op_context_new (OP_COPY
);
790 tctx
= file_op_total_context_new ();
791 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
792 tctx
->ask_overwrite
= FALSE
;
793 copy_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
794 file_op_total_context_destroy (tctx
);
795 file_op_context_destroy (ctx
);
799 g_free (selected_ptr_name
);
802 /* --------------------------------------------------------------------------------------------- */
805 tree_move (WTree
* tree
, const char *default_dest
)
807 char msg
[BUF_MEDIUM
];
808 char *dest
, *selected_ptr_name
;
811 FileOpTotalContext
*tctx
;
813 if (tree
->selected_ptr
== NULL
)
816 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
818 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
819 str_trunc (selected_ptr_name
, 50));
821 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
823 if (dest
== NULL
|| *dest
== '\0')
826 if (stat (dest
, &buf
))
828 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
829 unix_error_string (errno
));
833 if (!S_ISDIR (buf
.st_mode
))
835 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
839 ctx
= file_op_context_new (OP_MOVE
);
840 tctx
= file_op_total_context_new ();
841 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
842 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
843 file_op_total_context_destroy (tctx
);
844 file_op_context_destroy (ctx
);
847 g_free (selected_ptr_name
);
851 /* --------------------------------------------------------------------------------------------- */
855 tree_mkdir (WTree
* tree
)
857 char old_dir
[MC_MAXPATHLEN
];
859 if (!tree
->selected_ptr
)
861 if (chdir (tree
->selected_ptr
->name
))
871 /* --------------------------------------------------------------------------------------------- */
874 tree_rmdir (void *data
)
878 FileOpTotalContext
*tctx
;
880 if (!tree
->selected_ptr
)
887 char *selected_ptr_name
;
889 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
890 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
891 g_free (selected_ptr_name
);
893 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
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
, tree
->selected_ptr
->name
) == FILE_CONT
)
905 file_op_total_context_destroy (tctx
);
906 file_op_context_destroy (ctx
);
909 /* --------------------------------------------------------------------------------------------- */
912 tree_move_up (WTree
* tree
)
914 tree_move_backward (tree
, 1);
919 /* --------------------------------------------------------------------------------------------- */
922 tree_move_down (WTree
* tree
)
924 tree_move_forward (tree
, 1);
929 /* --------------------------------------------------------------------------------------------- */
932 tree_move_home (WTree
* tree
)
934 tree_move_to_top (tree
);
939 /* --------------------------------------------------------------------------------------------- */
942 tree_move_end (WTree
* tree
)
944 tree_move_to_bottom (tree
);
949 /* --------------------------------------------------------------------------------------------- */
952 tree_move_pgup (WTree
* tree
)
954 tree_move_backward (tree
, tlines (tree
) - 1);
959 /* --------------------------------------------------------------------------------------------- */
962 tree_move_pgdn (WTree
* tree
)
964 tree_move_forward (tree
, tlines (tree
) - 1);
969 /* --------------------------------------------------------------------------------------------- */
972 tree_move_left (WTree
* tree
)
976 if (tree_navigation_flag
)
978 v
= tree_move_to_parent (tree
);
986 /* --------------------------------------------------------------------------------------------- */
989 tree_move_right (WTree
* tree
)
993 if (tree_navigation_flag
)
995 tree_move_to_child (tree
);
1004 /* --------------------------------------------------------------------------------------------- */
1007 tree_start_search (WTree
* tree
)
1011 if (tree
->searching
)
1013 if (tree
->selected_ptr
== tree
->store
->tree_last
)
1014 tree_move_to_top (tree
);
1017 /* set navigation mode temporarily to 'Static' because in
1018 * dynamic navigation mode tree_move_forward will not move
1019 * to a lower sublevel if necessary (sequent searches must
1020 * start with the directory followed the last found directory)
1022 i
= tree_navigation_flag
;
1023 tree_navigation_flag
= 0;
1024 tree_move_forward (tree
, 1);
1025 tree_navigation_flag
= i
;
1027 tree_do_search (tree
, 0);
1031 tree
->searching
= 1;
1032 tree
->search_buffer
[0] = 0;
1036 /* --------------------------------------------------------------------------------------------- */
1039 tree_toggle_navig (WTree
* tree
)
1041 tree_navigation_flag
= !tree_navigation_flag
;
1042 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1043 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1044 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1047 /* --------------------------------------------------------------------------------------------- */
1050 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1052 cb_ret_t res
= MSG_HANDLED
;
1054 if (command
!= CK_Search
)
1055 tree
->searching
= 0;
1061 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1062 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1068 case CK_ToggleNavigation
:
1069 tree_toggle_navig (tree
);
1072 tree_copy (tree
, "");
1075 tree_move (tree
, "");
1078 tree_move_up (tree
);
1081 tree_move_down (tree
);
1084 tree_move_home (tree
);
1087 tree_move_end (tree
);
1090 tree_move_pgup (tree
);
1093 tree_move_pgdn (tree
);
1096 tree_chdir_sel (tree
);
1102 tree_start_search (tree
);
1108 if (!tree
->is_panel
)
1109 dlg_stop (((Widget
*) tree
)->owner
);
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
, tree_event
);
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 /* --------------------------------------------------------------------------------------------- */