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() */
59 #include "src/setup.h" /* confirm_delete, panels_options */
60 #include "src/keybind-defaults.h"
61 #include "src/history.h"
64 #include "midnight.h" /* the_menubar */
65 #include "file.h" /* copy_dir_dir(), move_dir_dir(), erase_dir() */
66 #include "layout.h" /* command_prompt */
67 #include "treestore.h"
73 /*** global variables ****************************************************************************/
75 /* The pointer to the tree */
76 WTree
*the_tree
= NULL
;
78 /* If this is true, then when browsing the tree the other window will
79 * automatically reload it's directory with the contents of the currently
84 /*** file scope macro definitions ****************************************************************/
86 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (panels_options.show_mini_info ? 2 : 0) : t->widget.lines)
88 /* Use the color of the parent widget for the unselected entries */
89 #define TREE_NORMALC(h) (h->color[DLG_COLOR_NORMAL])
90 #define TREE_CURRENTC(h) (h->color[DLG_COLOR_FOCUS])
92 /*** file scope type declarations ****************************************************************/
97 struct TreeStore
*store
;
98 tree_entry
*selected_ptr
; /* The selected directory */
99 char search_buffer
[MC_MAXFILENAMELEN
]; /* Current search string */
100 tree_entry
**tree_shown
; /* Entries currently on screen */
101 int is_panel
; /* panel or plain widget flag */
102 int active
; /* if it's currently selected */
103 int searching
; /* Are we on searching mode? */
104 int topdiff
; /* The difference between the topmost
105 shown and the selected */
108 /*** file scope variables ************************************************************************/
110 /* Specifies the display mode: 1d or 2d */
111 static gboolean tree_navigation_flag
= FALSE
;
113 /*** file scope functions ************************************************************************/
114 /* --------------------------------------------------------------------------------------------- */
116 static void tree_rescan (void *data
);
118 /* --------------------------------------------------------------------------------------------- */
121 back_ptr (tree_entry
* ptr
, int *count
)
125 while (ptr
&& ptr
->prev
&& i
< *count
)
134 /* --------------------------------------------------------------------------------------------- */
137 forw_ptr (tree_entry
* ptr
, int *count
)
141 while (ptr
&& ptr
->next
&& i
< *count
)
150 /* --------------------------------------------------------------------------------------------- */
153 remove_callback (tree_entry
* entry
, void *data
)
157 if (tree
->selected_ptr
== entry
)
159 if (tree
->selected_ptr
->next
)
160 tree
->selected_ptr
= tree
->selected_ptr
->next
;
162 tree
->selected_ptr
= tree
->selected_ptr
->prev
;
166 /* --------------------------------------------------------------------------------------------- */
167 /** Save the ${XDG_CACHE_HOME}/mc/Tree file */
170 save_tree (WTree
* tree
)
176 error
= tree_store_save ();
181 tree_name
= mc_config_get_full_path (MC_TREESTORE_FILE
);
182 fprintf (stderr
, _("Cannot open the %s file for writing:\n%s\n"), tree_name
,
183 unix_error_string (error
));
188 /* --------------------------------------------------------------------------------------------- */
191 tree_remove_entry (WTree
* tree
, char *name
)
194 tree_store_remove_entry (name
);
197 /* --------------------------------------------------------------------------------------------- */
200 tree_destroy (WTree
* tree
)
202 tree_store_remove_entry_remove_hook (remove_callback
);
205 g_free (tree
->tree_shown
);
206 tree
->tree_shown
= 0;
207 tree
->selected_ptr
= NULL
;
210 /* --------------------------------------------------------------------------------------------- */
211 /** Loads the .mc.tree file */
214 load_tree (WTree
* tree
)
218 tree
->selected_ptr
= tree
->store
->tree_first
;
219 tree_chdir (tree
, mc_config_get_home_dir ());
222 /* --------------------------------------------------------------------------------------------- */
225 tree_show_mini_info (WTree
* tree
, int tree_lines
, int tree_cols
)
227 Dlg_head
*h
= tree
->widget
.owner
;
233 if (!panels_options
.show_mini_info
)
235 line
= tree_lines
+ 2;
238 line
= tree_lines
+ 1;
242 /* Show search string */
243 tty_setcolor (INPUT_COLOR
);
244 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
245 widget_move (&tree
->widget
, line
, 1);
246 tty_print_char (PATH_SEP
);
247 tty_print_string (str_fit_to_term (tree
->search_buffer
, tree_cols
- 2, J_LEFT_FIT
));
248 tty_print_char (' ');
252 /* Show full name of selected directory */
253 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
254 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
255 widget_move (&tree
->widget
, line
, 1);
256 tty_print_string (str_fit_to_term (tree
->selected_ptr
->name
, tree_cols
, J_LEFT_FIT
));
260 /* --------------------------------------------------------------------------------------------- */
263 show_tree (WTree
* tree
)
265 Dlg_head
*h
= tree
->widget
.owner
;
267 int i
, j
, topsublevel
;
269 int tree_lines
, tree_cols
;
272 tree_lines
= tlines (tree
);
273 tree_cols
= tree
->widget
.cols
;
275 widget_move ((Widget
*) tree
, y
, x
);
282 g_free (tree
->tree_shown
);
283 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
285 if (tree
->store
->tree_first
)
286 topsublevel
= tree
->store
->tree_first
->sublevel
;
289 if (!tree
->selected_ptr
)
291 tree
->selected_ptr
= tree
->store
->tree_first
;
294 current
= tree
->selected_ptr
;
296 /* Calculate the directory which is to be shown on the topmost line */
297 if (!tree_navigation_flag
)
298 current
= back_ptr (current
, &tree
->topdiff
);
302 while (current
->prev
&& i
< tree
->topdiff
)
304 current
= current
->prev
;
305 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
307 if (strncmp (current
->name
, tree
->selected_ptr
->name
, strlen (current
->name
)) == 0)
310 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
312 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--);
313 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
316 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
317 && strlen (tree
->selected_ptr
->name
) > 1)
319 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
320 strlen (tree
->selected_ptr
->name
)) == 0)
327 /* Loop for every line */
328 for (i
= 0; i
< tree_lines
; i
++)
330 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
332 /* Move to the beginning of the line */
333 tty_draw_hline (tree
->widget
.y
+ y
+ i
, tree
->widget
.x
+ x
, ' ', tree_cols
);
339 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
340 ? SELECTED_COLOR
: NORMAL_COLOR
);
342 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
344 tree
->tree_shown
[i
] = current
;
345 if (current
->sublevel
== topsublevel
)
348 tty_print_string (str_fit_to_term
349 (current
->name
, tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
353 /* Sub level directory */
354 tty_set_alt_charset (TRUE
);
356 /* Output branch parts */
357 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
359 if (tree_cols
- 8 - 3 * j
< 9)
361 tty_print_char (' ');
362 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
363 tty_print_char (ACS_VLINE
);
365 tty_print_char (' ');
366 tty_print_char (' ');
368 tty_print_char (' ');
370 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
371 tty_print_char (ACS_LLCORNER
);
373 tty_print_char (ACS_LTEE
);
374 tty_print_char (ACS_HLINE
);
375 tty_set_alt_charset (FALSE
);
378 tty_print_char (' ');
379 tty_print_string (str_fit_to_term
380 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
383 /* Calculate the next value for current */
384 current
= current
->next
;
385 if (tree_navigation_flag
)
387 while (current
!= NULL
)
389 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
391 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
392 strlen (current
->name
)) == 0)
395 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
397 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--)
399 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
402 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
403 && strlen (tree
->selected_ptr
->name
) > 1)
405 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
406 strlen (tree
->selected_ptr
->name
)) == 0)
409 current
= current
->next
;
414 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
417 /* --------------------------------------------------------------------------------------------- */
420 tree_check_focus (WTree
* tree
)
422 if (tree
->topdiff
< 3)
424 else if (tree
->topdiff
>= tlines (tree
) - 3)
425 tree
->topdiff
= tlines (tree
) - 3 - 1;
428 /* --------------------------------------------------------------------------------------------- */
431 tree_move_backward (WTree
* tree
, int i
)
433 if (!tree_navigation_flag
)
434 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
440 current
= tree
->selected_ptr
;
441 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
443 current
= current
->prev
;
444 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
446 tree
->selected_ptr
= current
;
454 tree_check_focus (tree
);
457 /* --------------------------------------------------------------------------------------------- */
460 tree_move_forward (WTree
* tree
, int i
)
462 if (!tree_navigation_flag
)
463 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
469 current
= tree
->selected_ptr
;
470 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
472 current
= current
->next
;
473 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
475 tree
->selected_ptr
= current
;
483 tree_check_focus (tree
);
486 /* --------------------------------------------------------------------------------------------- */
489 tree_move_to_child (WTree
* tree
)
493 /* Do we have a starting point? */
494 if (!tree
->selected_ptr
)
496 /* Take the next entry */
497 current
= tree
->selected_ptr
->next
;
498 /* Is it the child of the selected entry */
499 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
501 /* Yes -> select this entry */
502 tree
->selected_ptr
= current
;
504 tree_check_focus (tree
);
508 /* No -> rescan and try again */
510 current
= tree
->selected_ptr
->next
;
511 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
513 tree
->selected_ptr
= current
;
515 tree_check_focus (tree
);
520 /* --------------------------------------------------------------------------------------------- */
523 tree_move_to_parent (WTree
* tree
)
528 if (!tree
->selected_ptr
)
531 old
= tree
->selected_ptr
;
532 current
= tree
->selected_ptr
->prev
;
533 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
535 current
= current
->prev
;
539 current
= tree
->store
->tree_first
;
540 tree
->selected_ptr
= current
;
541 tree_check_focus (tree
);
542 return tree
->selected_ptr
!= old
;
545 /* --------------------------------------------------------------------------------------------- */
548 tree_move_to_top (WTree
* tree
)
550 tree
->selected_ptr
= tree
->store
->tree_first
;
554 /* --------------------------------------------------------------------------------------------- */
557 tree_move_to_bottom (WTree
* tree
)
559 tree
->selected_ptr
= tree
->store
->tree_last
;
560 tree
->topdiff
= tlines (tree
) - 3 - 1;
563 /* --------------------------------------------------------------------------------------------- */
564 /** Handle mouse click */
567 tree_event (WTree
* tree
, int y
)
569 if (tree
->tree_shown
[y
])
571 tree
->selected_ptr
= tree
->tree_shown
[y
];
577 /* --------------------------------------------------------------------------------------------- */
580 tree_chdir_sel (WTree
* tree
)
587 if (do_cd (tree
->selected_ptr
->name
, cd_exact
))
588 select_item (current_panel
);
590 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
591 tree
->selected_ptr
->name
, unix_error_string (errno
));
597 /* --------------------------------------------------------------------------------------------- */
600 maybe_chdir (WTree
* tree
)
602 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
603 tree_chdir_sel (tree
);
606 /* --------------------------------------------------------------------------------------------- */
607 /** Mouse callback */
610 event_callback (Gpm_Event
* event
, void *data
)
614 /* rest of the upper frame, the menu is invisible - call menu */
615 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) && event
->y
== 1 && !menubar_visible
)
617 event
->x
+= tree
->widget
.x
;
618 return the_menubar
->widget
.mouse (event
, the_menubar
);
621 if (!(event
->type
& GPM_UP
))
634 tree_move_backward (tree
, tlines (tree
) - 1);
637 else if (event
->y
>= tlines (tree
))
639 tree_move_forward (tree
, tlines (tree
) - 1);
644 tree_event (tree
, event
->y
);
645 if ((event
->type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
647 tree_chdir_sel (tree
);
653 /* --------------------------------------------------------------------------------------------- */
654 /** Search tree for text */
657 search_tree (WTree
* tree
, char *text
)
665 current
= tree
->selected_ptr
;
667 while (!wrapped
|| current
!= tree
->selected_ptr
)
669 if (strncmp (current
->subname
, text
, len
) == 0)
671 tree
->selected_ptr
= current
;
675 current
= current
->next
;
678 current
= tree
->store
->tree_first
;
683 tree_check_focus (tree
);
687 /* --------------------------------------------------------------------------------------------- */
690 tree_do_search (WTree
* tree
, int key
)
694 l
= strlen (tree
->search_buffer
);
695 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
696 tree
->search_buffer
[--l
] = '\0';
697 else if (key
&& l
< sizeof (tree
->search_buffer
))
699 tree
->search_buffer
[l
] = key
;
700 tree
->search_buffer
[++l
] = '\0';
703 if (!search_tree (tree
, tree
->search_buffer
))
704 tree
->search_buffer
[--l
] = 0;
710 /* --------------------------------------------------------------------------------------------- */
713 tree_rescan (void *data
)
716 char old_dir
[MC_MAXPATHLEN
];
720 if (tree
->selected_ptr
== NULL
|| mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
723 vpath
= vfs_path_from_str (tree
->selected_ptr
->name
);
724 if (mc_chdir (vpath
) != 0)
726 vfs_path_free (vpath
);
730 tree_store_rescan (vpath
);
731 vpath
= vfs_path_from_str (old_dir
);
732 ret
= mc_chdir (vpath
);
733 vfs_path_free (vpath
);
736 /* --------------------------------------------------------------------------------------------- */
739 tree_forget (void *data
)
742 if (tree
->selected_ptr
)
743 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
746 /* --------------------------------------------------------------------------------------------- */
749 tree_copy (WTree
* tree
, const char *default_dest
)
751 char msg
[BUF_MEDIUM
];
754 if (tree
->selected_ptr
== NULL
)
757 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
758 str_trunc (tree
->selected_ptr
->name
, 50));
759 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
760 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
762 if (dest
!= NULL
&& *dest
!= '\0')
765 FileOpTotalContext
*tctx
;
767 ctx
= file_op_context_new (OP_COPY
);
768 tctx
= file_op_total_context_new ();
769 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
770 tctx
->ask_overwrite
= FALSE
;
771 copy_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
772 file_op_total_context_destroy (tctx
);
773 file_op_context_destroy (ctx
);
779 /* --------------------------------------------------------------------------------------------- */
782 tree_move (WTree
* tree
, const char *default_dest
)
784 char msg
[BUF_MEDIUM
];
788 FileOpTotalContext
*tctx
;
790 if (tree
->selected_ptr
== NULL
)
793 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
794 str_trunc (tree
->selected_ptr
->name
, 50));
796 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
798 if (dest
== NULL
|| *dest
== '\0')
804 if (stat (dest
, &buf
))
806 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
807 unix_error_string (errno
));
812 if (!S_ISDIR (buf
.st_mode
))
814 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
819 ctx
= file_op_context_new (OP_MOVE
);
820 tctx
= file_op_total_context_new ();
821 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
822 move_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
);
823 file_op_total_context_destroy (tctx
);
824 file_op_context_destroy (ctx
);
829 /* --------------------------------------------------------------------------------------------- */
833 tree_mkdir (WTree
* tree
)
835 char old_dir
[MC_MAXPATHLEN
];
837 if (!tree
->selected_ptr
)
839 if (mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
841 if (chdir (tree
->selected_ptr
->name
))
851 /* --------------------------------------------------------------------------------------------- */
854 tree_rmdir (void *data
)
858 FileOpTotalContext
*tctx
;
860 if (!tree
->selected_ptr
)
868 buf
= g_strdup_printf (_("Delete %s?"), tree
->selected_ptr
->name
);
869 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
875 ctx
= file_op_context_new (OP_DELETE
);
876 tctx
= file_op_total_context_new ();
878 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
879 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
881 file_op_total_context_destroy (tctx
);
882 file_op_context_destroy (ctx
);
885 /* --------------------------------------------------------------------------------------------- */
888 tree_move_up (WTree
* tree
)
890 tree_move_backward (tree
, 1);
895 /* --------------------------------------------------------------------------------------------- */
898 tree_move_down (WTree
* tree
)
900 tree_move_forward (tree
, 1);
905 /* --------------------------------------------------------------------------------------------- */
908 tree_move_home (WTree
* tree
)
910 tree_move_to_top (tree
);
915 /* --------------------------------------------------------------------------------------------- */
918 tree_move_end (WTree
* tree
)
920 tree_move_to_bottom (tree
);
925 /* --------------------------------------------------------------------------------------------- */
928 tree_move_pgup (WTree
* tree
)
930 tree_move_backward (tree
, tlines (tree
) - 1);
935 /* --------------------------------------------------------------------------------------------- */
938 tree_move_pgdn (WTree
* tree
)
940 tree_move_forward (tree
, tlines (tree
) - 1);
945 /* --------------------------------------------------------------------------------------------- */
948 tree_move_left (WTree
* tree
)
952 if (tree_navigation_flag
)
954 v
= tree_move_to_parent (tree
);
962 /* --------------------------------------------------------------------------------------------- */
965 tree_move_right (WTree
* tree
)
969 if (tree_navigation_flag
)
971 tree_move_to_child (tree
);
980 /* --------------------------------------------------------------------------------------------- */
983 tree_start_search (WTree
* tree
)
989 if (tree
->selected_ptr
== tree
->store
->tree_last
)
990 tree_move_to_top (tree
);
993 /* set navigation mode temporarily to 'Static' because in
994 * dynamic navigation mode tree_move_forward will not move
995 * to a lower sublevel if necessary (sequent searches must
996 * start with the directory followed the last found directory)
998 i
= tree_navigation_flag
;
999 tree_navigation_flag
= 0;
1000 tree_move_forward (tree
, 1);
1001 tree_navigation_flag
= i
;
1003 tree_do_search (tree
, 0);
1007 tree
->searching
= 1;
1008 tree
->search_buffer
[0] = 0;
1012 /* --------------------------------------------------------------------------------------------- */
1015 tree_toggle_navig (WTree
* tree
)
1017 tree_navigation_flag
= !tree_navigation_flag
;
1018 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1019 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1020 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1023 /* --------------------------------------------------------------------------------------------- */
1026 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1028 cb_ret_t res
= MSG_HANDLED
;
1030 if (command
!= CK_Search
)
1031 tree
->searching
= 0;
1037 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1038 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1044 case CK_ToggleNavigation
:
1045 tree_toggle_navig (tree
);
1048 tree_copy (tree
, "");
1051 tree_move (tree
, "");
1054 tree_move_up (tree
);
1057 tree_move_down (tree
);
1060 tree_move_home (tree
);
1063 tree_move_end (tree
);
1066 tree_move_pgup (tree
);
1069 tree_move_pgdn (tree
);
1072 tree_chdir_sel (tree
);
1078 tree_start_search (tree
);
1084 /* don't close tree due to SIGINT */
1087 res
= MSG_NOT_HANDLED
;
1095 /* --------------------------------------------------------------------------------------------- */
1098 tree_key (WTree
* tree
, int key
)
1102 if (is_abort_char (key
))
1106 tree
->searching
= 0;
1108 return MSG_HANDLED
; /* eat abort char */
1110 /* modal tree dialog: let upper layer see the
1111 abort character and close the dialog */
1112 return MSG_NOT_HANDLED
;
1115 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1117 tree_do_search (tree
, key
);
1122 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1123 if (key
== tree_map
[i
].key
)
1124 switch (tree_map
[i
].command
)
1127 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1129 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1131 tree_execute_cmd (tree
, tree_map
[i
].command
);
1135 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1136 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1138 tree_start_search (tree
);
1139 tree_do_search (tree
, key
);
1143 return MSG_NOT_HANDLED
;
1146 /* --------------------------------------------------------------------------------------------- */
1149 tree_frame (Dlg_head
* h
, WTree
* tree
)
1151 tty_setcolor (NORMAL_COLOR
);
1152 widget_erase ((Widget
*) tree
);
1155 const char *title
= _("Directory tree");
1156 const int len
= str_term_width1 (title
);
1158 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1160 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1161 tty_printf (" %s ", title
);
1163 if (panels_options
.show_mini_info
)
1164 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1165 tty_print_alt_char (ACS_LTEE
, FALSE
);
1166 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1167 tty_print_alt_char (ACS_RTEE
, FALSE
);
1168 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1169 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1173 /* --------------------------------------------------------------------------------------------- */
1176 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1178 WTree
*tree
= (WTree
*) w
;
1179 Dlg_head
*h
= tree
->widget
.owner
;
1180 WButtonBar
*b
= find_buttonbar (h
);
1185 tree_frame (h
, tree
);
1191 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1192 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1193 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1194 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1195 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1196 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1197 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1199 /* FIXME: mkdir is currently defunct */
1200 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1202 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1204 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1205 buttonbar_redraw (b
);
1207 /* FIXME: Should find a better way of only displaying the
1208 currently selected item */
1212 /* FIXME: Should find a better way of changing the color of the
1215 case WIDGET_UNFOCUS
:
1217 tree
->searching
= 0;
1222 return tree_key (tree
, parm
);
1224 case WIDGET_COMMAND
:
1225 /* command from buttonbar */
1226 return tree_execute_cmd (tree
, parm
);
1228 case WIDGET_DESTROY
:
1229 tree_destroy (tree
);
1233 return default_proc (msg
, parm
);
1237 /* --------------------------------------------------------------------------------------------- */
1238 /*** public functions ****************************************************************************/
1239 /* --------------------------------------------------------------------------------------------- */
1242 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1244 WTree
*tree
= g_new (WTree
, 1);
1246 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1247 tree
->is_panel
= is_panel
;
1248 tree
->selected_ptr
= 0;
1250 tree
->store
= tree_store_get ();
1251 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1252 tree
->tree_shown
= 0;
1253 tree
->search_buffer
[0] = 0;
1254 tree
->topdiff
= tree
->widget
.lines
/ 2;
1255 tree
->searching
= 0;
1258 /* We do not want to keep the cursor */
1259 widget_want_cursor (tree
->widget
, 0);
1264 /* --------------------------------------------------------------------------------------------- */
1267 tree_chdir (WTree
* tree
, const char *dir
)
1269 tree_entry
*current
;
1271 current
= tree_store_whereis (dir
);
1273 if (current
!= NULL
)
1275 tree
->selected_ptr
= current
;
1276 tree_check_focus (tree
);
1280 /* --------------------------------------------------------------------------------------------- */
1281 /** Return name of the currently selected entry */
1284 tree_selected_name (const WTree
* tree
)
1286 return tree
->selected_ptr
->name
;
1289 /* --------------------------------------------------------------------------------------------- */
1292 sync_tree (const char *path
)
1294 tree_chdir (the_tree
, path
);
1297 /* --------------------------------------------------------------------------------------------- */
1300 find_tree (struct Dlg_head
*h
)
1302 return (WTree
*) find_widget_type (h
, tree_callback
);
1305 /* --------------------------------------------------------------------------------------------- */