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
];
721 if (tree
->selected_ptr
== NULL
|| mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
724 vpath
= vfs_path_from_str (tree
->selected_ptr
->name
);
725 ok
= (mc_chdir (vpath
) == 0);
726 vfs_path_free (vpath
);
730 tree_store_rescan (tree
->selected_ptr
->name
);
731 vpath
= vfs_path_from_str (old_dir
);
732 ret
= mc_chdir (vpath
);
733 vfs_path_free (vpath
);
737 /* --------------------------------------------------------------------------------------------- */
740 tree_forget (void *data
)
743 if (tree
->selected_ptr
)
744 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
747 /* --------------------------------------------------------------------------------------------- */
750 tree_copy (WTree
* tree
, const char *default_dest
)
752 char msg
[BUF_MEDIUM
];
755 if (tree
->selected_ptr
== NULL
)
758 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
759 str_trunc (tree
->selected_ptr
->name
, 50));
760 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
761 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
763 if (dest
!= NULL
&& *dest
!= '\0')
766 FileOpTotalContext
*tctx
;
768 ctx
= file_op_context_new (OP_COPY
);
769 tctx
= file_op_total_context_new ();
770 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
771 tctx
->ask_overwrite
= FALSE
;
772 copy_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
773 file_op_total_context_destroy (tctx
);
774 file_op_context_destroy (ctx
);
780 /* --------------------------------------------------------------------------------------------- */
783 tree_move (WTree
* tree
, const char *default_dest
)
785 char msg
[BUF_MEDIUM
];
789 FileOpTotalContext
*tctx
;
791 if (tree
->selected_ptr
== NULL
)
794 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
795 str_trunc (tree
->selected_ptr
->name
, 50));
797 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
799 if (dest
== NULL
|| *dest
== '\0')
805 if (stat (dest
, &buf
))
807 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
808 unix_error_string (errno
));
813 if (!S_ISDIR (buf
.st_mode
))
815 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
820 ctx
= file_op_context_new (OP_MOVE
);
821 tctx
= file_op_total_context_new ();
822 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
823 move_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
);
824 file_op_total_context_destroy (tctx
);
825 file_op_context_destroy (ctx
);
830 /* --------------------------------------------------------------------------------------------- */
834 tree_mkdir (WTree
* tree
)
836 char old_dir
[MC_MAXPATHLEN
];
838 if (!tree
->selected_ptr
)
840 if (mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
842 if (chdir (tree
->selected_ptr
->name
))
852 /* --------------------------------------------------------------------------------------------- */
855 tree_rmdir (void *data
)
859 FileOpTotalContext
*tctx
;
861 if (!tree
->selected_ptr
)
869 buf
= g_strdup_printf (_("Delete %s?"), tree
->selected_ptr
->name
);
870 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
876 ctx
= file_op_context_new (OP_DELETE
);
877 tctx
= file_op_total_context_new ();
879 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
880 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
882 file_op_total_context_destroy (tctx
);
883 file_op_context_destroy (ctx
);
886 /* --------------------------------------------------------------------------------------------- */
889 tree_move_up (WTree
* tree
)
891 tree_move_backward (tree
, 1);
896 /* --------------------------------------------------------------------------------------------- */
899 tree_move_down (WTree
* tree
)
901 tree_move_forward (tree
, 1);
906 /* --------------------------------------------------------------------------------------------- */
909 tree_move_home (WTree
* tree
)
911 tree_move_to_top (tree
);
916 /* --------------------------------------------------------------------------------------------- */
919 tree_move_end (WTree
* tree
)
921 tree_move_to_bottom (tree
);
926 /* --------------------------------------------------------------------------------------------- */
929 tree_move_pgup (WTree
* tree
)
931 tree_move_backward (tree
, tlines (tree
) - 1);
936 /* --------------------------------------------------------------------------------------------- */
939 tree_move_pgdn (WTree
* tree
)
941 tree_move_forward (tree
, tlines (tree
) - 1);
946 /* --------------------------------------------------------------------------------------------- */
949 tree_move_left (WTree
* tree
)
953 if (tree_navigation_flag
)
955 v
= tree_move_to_parent (tree
);
963 /* --------------------------------------------------------------------------------------------- */
966 tree_move_right (WTree
* tree
)
970 if (tree_navigation_flag
)
972 tree_move_to_child (tree
);
981 /* --------------------------------------------------------------------------------------------- */
984 tree_start_search (WTree
* tree
)
990 if (tree
->selected_ptr
== tree
->store
->tree_last
)
991 tree_move_to_top (tree
);
994 /* set navigation mode temporarily to 'Static' because in
995 * dynamic navigation mode tree_move_forward will not move
996 * to a lower sublevel if necessary (sequent searches must
997 * start with the directory followed the last found directory)
999 i
= tree_navigation_flag
;
1000 tree_navigation_flag
= 0;
1001 tree_move_forward (tree
, 1);
1002 tree_navigation_flag
= i
;
1004 tree_do_search (tree
, 0);
1008 tree
->searching
= 1;
1009 tree
->search_buffer
[0] = 0;
1013 /* --------------------------------------------------------------------------------------------- */
1016 tree_toggle_navig (WTree
* tree
)
1018 tree_navigation_flag
= !tree_navigation_flag
;
1019 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1020 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1021 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1024 /* --------------------------------------------------------------------------------------------- */
1027 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1029 cb_ret_t res
= MSG_HANDLED
;
1031 if (command
!= CK_Search
)
1032 tree
->searching
= 0;
1038 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1039 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1045 case CK_ToggleNavigation
:
1046 tree_toggle_navig (tree
);
1049 tree_copy (tree
, "");
1052 tree_move (tree
, "");
1055 tree_move_up (tree
);
1058 tree_move_down (tree
);
1061 tree_move_home (tree
);
1064 tree_move_end (tree
);
1067 tree_move_pgup (tree
);
1070 tree_move_pgdn (tree
);
1073 tree_chdir_sel (tree
);
1079 tree_start_search (tree
);
1085 /* don't close tree due to SIGINT */
1088 res
= MSG_NOT_HANDLED
;
1096 /* --------------------------------------------------------------------------------------------- */
1099 tree_key (WTree
* tree
, int key
)
1103 if (is_abort_char (key
))
1107 tree
->searching
= 0;
1109 return MSG_HANDLED
; /* eat abort char */
1111 /* modal tree dialog: let upper layer see the
1112 abort character and close the dialog */
1113 return MSG_NOT_HANDLED
;
1116 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1118 tree_do_search (tree
, key
);
1123 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1124 if (key
== tree_map
[i
].key
)
1125 switch (tree_map
[i
].command
)
1128 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1130 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1132 tree_execute_cmd (tree
, tree_map
[i
].command
);
1136 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1137 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1139 tree_start_search (tree
);
1140 tree_do_search (tree
, key
);
1144 return MSG_NOT_HANDLED
;
1147 /* --------------------------------------------------------------------------------------------- */
1150 tree_frame (Dlg_head
* h
, WTree
* tree
)
1152 tty_setcolor (NORMAL_COLOR
);
1153 widget_erase ((Widget
*) tree
);
1156 const char *title
= _("Directory tree");
1157 const int len
= str_term_width1 (title
);
1159 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1161 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1162 tty_printf (" %s ", title
);
1164 if (panels_options
.show_mini_info
)
1165 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1166 tty_print_alt_char (ACS_LTEE
, FALSE
);
1167 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1168 tty_print_alt_char (ACS_RTEE
, FALSE
);
1169 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1170 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1174 /* --------------------------------------------------------------------------------------------- */
1177 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1179 WTree
*tree
= (WTree
*) w
;
1180 Dlg_head
*h
= tree
->widget
.owner
;
1181 WButtonBar
*b
= find_buttonbar (h
);
1186 tree_frame (h
, tree
);
1192 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1193 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1194 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1195 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1196 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1197 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1198 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1200 /* FIXME: mkdir is currently defunct */
1201 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1203 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1205 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1206 buttonbar_redraw (b
);
1208 /* FIXME: Should find a better way of only displaying the
1209 currently selected item */
1213 /* FIXME: Should find a better way of changing the color of the
1216 case WIDGET_UNFOCUS
:
1218 tree
->searching
= 0;
1223 return tree_key (tree
, parm
);
1225 case WIDGET_COMMAND
:
1226 /* command from buttonbar */
1227 return tree_execute_cmd (tree
, parm
);
1229 case WIDGET_DESTROY
:
1230 tree_destroy (tree
);
1234 return default_proc (msg
, parm
);
1238 /* --------------------------------------------------------------------------------------------- */
1239 /*** public functions ****************************************************************************/
1240 /* --------------------------------------------------------------------------------------------- */
1243 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1245 WTree
*tree
= g_new (WTree
, 1);
1247 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1248 tree
->is_panel
= is_panel
;
1249 tree
->selected_ptr
= 0;
1251 tree
->store
= tree_store_get ();
1252 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1253 tree
->tree_shown
= 0;
1254 tree
->search_buffer
[0] = 0;
1255 tree
->topdiff
= tree
->widget
.lines
/ 2;
1256 tree
->searching
= 0;
1259 /* We do not want to keep the cursor */
1260 widget_want_cursor (tree
->widget
, 0);
1265 /* --------------------------------------------------------------------------------------------- */
1268 tree_chdir (WTree
* tree
, const char *dir
)
1270 tree_entry
*current
;
1272 current
= tree_store_whereis (dir
);
1274 if (current
!= NULL
)
1276 tree
->selected_ptr
= current
;
1277 tree_check_focus (tree
);
1281 /* --------------------------------------------------------------------------------------------- */
1282 /** Return name of the currently selected entry */
1285 tree_selected_name (const WTree
* tree
)
1287 return tree
->selected_ptr
->name
;
1290 /* --------------------------------------------------------------------------------------------- */
1293 sync_tree (const char *path
)
1295 tree_chdir (the_tree
, path
);
1298 /* --------------------------------------------------------------------------------------------- */
1301 find_tree (struct Dlg_head
*h
)
1303 return (WTree
*) find_widget_type (h
, tree_callback
);
1306 /* --------------------------------------------------------------------------------------------- */