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 ? WIDGET (t)->lines - 2 - \
86 (panels_options.show_mini_info ? 2 : 0) : WIDGET (t)->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
, const vfs_path_t
* name_vpath
)
194 tree_store_remove_entry (name_vpath
);
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 Widget
*w
= WIDGET (tree
);
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 (w
->y
+ line
, w
->x
+ 1, ' ', tree_cols
);
245 widget_move (w
, 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 WDialog
*h
= w
->owner
;
256 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
257 tty_draw_hline (w
->y
+ line
, w
->x
+ 1, ' ', tree_cols
);
258 widget_move (w
, line
, 1);
259 tmp_path
= vfs_path_to_str (tree
->selected_ptr
->name
);
260 tty_print_string (str_fit_to_term (tmp_path
, tree_cols
, J_LEFT_FIT
));
265 /* --------------------------------------------------------------------------------------------- */
268 show_tree (WTree
* tree
)
270 Widget
*w
= WIDGET (tree
);
271 WDialog
*h
= w
->owner
;
273 int i
, j
, topsublevel
;
275 int tree_lines
, tree_cols
;
278 tree_lines
= tlines (tree
);
281 widget_move (w
, y
, x
);
288 g_free (tree
->tree_shown
);
289 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
291 if (tree
->store
->tree_first
)
292 topsublevel
= tree
->store
->tree_first
->sublevel
;
295 if (!tree
->selected_ptr
)
297 tree
->selected_ptr
= tree
->store
->tree_first
;
300 current
= tree
->selected_ptr
;
302 /* Calculate the directory which is to be shown on the topmost line */
303 if (!tree_navigation_flag
)
304 current
= back_ptr (current
, &tree
->topdiff
);
308 while (current
->prev
&& i
< tree
->topdiff
)
312 current
= current
->prev
;
313 current_name
= vfs_path_to_str (current
->name
);
315 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
317 if (vfs_path_cmp (current
->name
, tree
->selected_ptr
->name
) == 0)
320 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
322 for (j
= strlen (current_name
) - 1; current_name
[j
] != PATH_SEP
; j
--);
323 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
328 if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
329 && vfs_path_len (tree
->selected_ptr
->name
) > 1)
331 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
,
332 vfs_path_len (tree
->selected_ptr
->name
)) == 0)
336 g_free (current_name
);
341 /* Loop for every line */
342 for (i
= 0; i
< tree_lines
; i
++)
344 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
346 /* Move to the beginning of the line */
347 tty_draw_hline (w
->y
+ y
+ i
, w
->x
+ x
, ' ', tree_cols
);
353 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
354 ? SELECTED_COLOR
: NORMAL_COLOR
);
356 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
358 tree
->tree_shown
[i
] = current
;
359 if (current
->sublevel
== topsublevel
)
364 current_name
= vfs_path_to_str (current
->name
);
365 tty_print_string (str_fit_to_term
366 (current_name
, tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
367 g_free (current_name
);
371 /* Sub level directory */
372 tty_set_alt_charset (TRUE
);
374 /* Output branch parts */
375 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
377 if (tree_cols
- 8 - 3 * j
< 9)
379 tty_print_char (' ');
380 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
381 tty_print_char (ACS_VLINE
);
383 tty_print_char (' ');
384 tty_print_char (' ');
386 tty_print_char (' ');
388 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
389 tty_print_char (ACS_LLCORNER
);
391 tty_print_char (ACS_LTEE
);
392 tty_print_char (ACS_HLINE
);
393 tty_set_alt_charset (FALSE
);
396 tty_print_char (' ');
397 tty_print_string (str_fit_to_term
398 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
401 /* Calculate the next value for current */
402 current
= current
->next
;
403 if (tree_navigation_flag
)
405 while (current
!= NULL
)
407 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
409 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
,
410 vfs_path_len (current
->name
)) == 0)
413 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
417 current_name
= vfs_path_to_str (current
->name
);
418 for (j
= strlen (current_name
) - 1; current_name
[j
] != PATH_SEP
; j
--)
420 g_free (current_name
);
421 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
424 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
425 && vfs_path_len (tree
->selected_ptr
->name
) > 1)
427 if (vfs_path_ncmp (current
->name
, tree
->selected_ptr
->name
,
428 vfs_path_len (tree
->selected_ptr
->name
)) == 0)
431 current
= current
->next
;
436 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
439 /* --------------------------------------------------------------------------------------------- */
442 tree_check_focus (WTree
* tree
)
444 if (tree
->topdiff
< 3)
446 else if (tree
->topdiff
>= tlines (tree
) - 3)
447 tree
->topdiff
= tlines (tree
) - 3 - 1;
450 /* --------------------------------------------------------------------------------------------- */
453 tree_move_backward (WTree
* tree
, int i
)
455 if (!tree_navigation_flag
)
456 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
462 current
= tree
->selected_ptr
;
463 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
465 current
= current
->prev
;
466 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
468 tree
->selected_ptr
= current
;
476 tree_check_focus (tree
);
479 /* --------------------------------------------------------------------------------------------- */
482 tree_move_forward (WTree
* tree
, int i
)
484 if (!tree_navigation_flag
)
485 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
491 current
= tree
->selected_ptr
;
492 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
494 current
= current
->next
;
495 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
497 tree
->selected_ptr
= current
;
505 tree_check_focus (tree
);
508 /* --------------------------------------------------------------------------------------------- */
511 tree_move_to_child (WTree
* tree
)
515 /* Do we have a starting point? */
516 if (!tree
->selected_ptr
)
518 /* Take the next entry */
519 current
= tree
->selected_ptr
->next
;
520 /* Is it the child of the selected entry */
521 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
523 /* Yes -> select this entry */
524 tree
->selected_ptr
= current
;
526 tree_check_focus (tree
);
530 /* No -> rescan and try again */
532 current
= tree
->selected_ptr
->next
;
533 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
535 tree
->selected_ptr
= current
;
537 tree_check_focus (tree
);
542 /* --------------------------------------------------------------------------------------------- */
545 tree_move_to_parent (WTree
* tree
)
550 if (!tree
->selected_ptr
)
553 old
= tree
->selected_ptr
;
554 current
= tree
->selected_ptr
->prev
;
555 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
557 current
= current
->prev
;
561 current
= tree
->store
->tree_first
;
562 tree
->selected_ptr
= current
;
563 tree_check_focus (tree
);
564 return tree
->selected_ptr
!= old
;
567 /* --------------------------------------------------------------------------------------------- */
570 tree_move_to_top (WTree
* tree
)
572 tree
->selected_ptr
= tree
->store
->tree_first
;
576 /* --------------------------------------------------------------------------------------------- */
579 tree_move_to_bottom (WTree
* tree
)
581 tree
->selected_ptr
= tree
->store
->tree_last
;
582 tree
->topdiff
= tlines (tree
) - 3 - 1;
585 /* --------------------------------------------------------------------------------------------- */
587 /** Handle mouse click */
589 tree_mouse_click (WTree
* tree
, int y
)
591 if (tree
->tree_shown
[y
])
593 tree
->selected_ptr
= tree
->tree_shown
[y
];
599 /* --------------------------------------------------------------------------------------------- */
602 tree_chdir_sel (WTree
* tree
)
611 tmp_path
= vfs_path_to_str (tree
->selected_ptr
->name
);
612 if (do_cd (tree
->selected_ptr
->name
, cd_exact
))
613 select_item (current_panel
);
615 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
616 tmp_path
, unix_error_string (errno
));
623 /* --------------------------------------------------------------------------------------------- */
626 maybe_chdir (WTree
* tree
)
628 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
629 tree_chdir_sel (tree
);
632 /* --------------------------------------------------------------------------------------------- */
633 /** Mouse callback */
636 tree_event (Gpm_Event
* event
, void *data
)
638 WTree
*tree
= (WTree
*) data
;
639 Widget
*w
= WIDGET (data
);
642 if (!mouse_global_in_widget (event
, w
))
643 return MOU_UNHANDLED
;
645 /* rest of the upper frame - call menu */
646 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) != 0 && event
->y
== WIDGET (w
->owner
)->y
+ 1)
647 return MOU_UNHANDLED
;
649 local
= mouse_get_local (event
, w
);
651 if ((local
.type
& GPM_UP
) == 0)
664 tree_move_backward (tree
, tlines (tree
) - 1);
667 else if (local
.y
>= tlines (tree
))
669 tree_move_forward (tree
, tlines (tree
) - 1);
674 tree_mouse_click (tree
, local
.y
);
675 if ((local
.type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
676 tree_chdir_sel (tree
);
682 /* --------------------------------------------------------------------------------------------- */
683 /** Search tree for text */
686 search_tree (WTree
* tree
, char *text
)
694 current
= tree
->selected_ptr
;
696 while (!wrapped
|| current
!= tree
->selected_ptr
)
698 if (strncmp (current
->subname
, text
, len
) == 0)
700 tree
->selected_ptr
= current
;
704 current
= current
->next
;
707 current
= tree
->store
->tree_first
;
712 tree_check_focus (tree
);
716 /* --------------------------------------------------------------------------------------------- */
719 tree_do_search (WTree
* tree
, int key
)
723 l
= strlen (tree
->search_buffer
);
724 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
725 tree
->search_buffer
[--l
] = '\0';
726 else if (key
&& l
< sizeof (tree
->search_buffer
))
728 tree
->search_buffer
[l
] = key
;
729 tree
->search_buffer
[++l
] = '\0';
732 if (!search_tree (tree
, tree
->search_buffer
))
733 tree
->search_buffer
[--l
] = 0;
739 /* --------------------------------------------------------------------------------------------- */
742 tree_rescan (void *data
)
745 vfs_path_t
*old_vpath
;
747 old_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
748 if (old_vpath
== NULL
)
751 if (tree
->selected_ptr
!= NULL
&& mc_chdir (tree
->selected_ptr
->name
) == 0)
755 tree_store_rescan (tree
->selected_ptr
->name
);
756 ret
= mc_chdir (old_vpath
);
759 vfs_path_free (old_vpath
);
762 /* --------------------------------------------------------------------------------------------- */
765 tree_forget (void *data
)
768 if (tree
->selected_ptr
)
769 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
772 /* --------------------------------------------------------------------------------------------- */
775 tree_copy (WTree
* tree
, const char *default_dest
)
777 char msg
[BUF_MEDIUM
];
778 char *dest
, *selected_ptr_name
;
780 if (tree
->selected_ptr
== NULL
)
783 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
785 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
786 str_trunc (selected_ptr_name
, 50));
787 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
788 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
790 if (dest
!= NULL
&& *dest
!= '\0')
793 FileOpTotalContext
*tctx
;
795 ctx
= file_op_context_new (OP_COPY
);
796 tctx
= file_op_total_context_new ();
797 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
798 tctx
->ask_overwrite
= FALSE
;
799 copy_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
800 file_op_total_context_destroy (tctx
);
801 file_op_context_destroy (ctx
);
805 g_free (selected_ptr_name
);
808 /* --------------------------------------------------------------------------------------------- */
811 tree_move (WTree
* tree
, const char *default_dest
)
813 char msg
[BUF_MEDIUM
];
814 char *dest
, *selected_ptr_name
;
817 FileOpTotalContext
*tctx
;
819 if (tree
->selected_ptr
== NULL
)
822 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
824 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
825 str_trunc (selected_ptr_name
, 50));
827 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
829 if (dest
== NULL
|| *dest
== '\0')
832 if (stat (dest
, &buf
))
834 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
835 unix_error_string (errno
));
839 if (!S_ISDIR (buf
.st_mode
))
841 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
845 ctx
= file_op_context_new (OP_MOVE
);
846 tctx
= file_op_total_context_new ();
847 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
848 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
849 file_op_total_context_destroy (tctx
);
850 file_op_context_destroy (ctx
);
853 g_free (selected_ptr_name
);
857 /* --------------------------------------------------------------------------------------------- */
861 tree_mkdir (WTree
* tree
)
863 char old_dir
[MC_MAXPATHLEN
];
865 if (!tree
->selected_ptr
)
867 if (chdir (tree
->selected_ptr
->name
))
877 /* --------------------------------------------------------------------------------------------- */
880 tree_rmdir (void *data
)
884 FileOpTotalContext
*tctx
;
886 if (!tree
->selected_ptr
)
893 char *selected_ptr_name
;
895 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
896 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
897 g_free (selected_ptr_name
);
899 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
905 ctx
= file_op_context_new (OP_DELETE
);
906 tctx
= file_op_total_context_new ();
908 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
909 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
911 file_op_total_context_destroy (tctx
);
912 file_op_context_destroy (ctx
);
915 /* --------------------------------------------------------------------------------------------- */
918 tree_move_up (WTree
* tree
)
920 tree_move_backward (tree
, 1);
925 /* --------------------------------------------------------------------------------------------- */
928 tree_move_down (WTree
* tree
)
930 tree_move_forward (tree
, 1);
935 /* --------------------------------------------------------------------------------------------- */
938 tree_move_home (WTree
* tree
)
940 tree_move_to_top (tree
);
945 /* --------------------------------------------------------------------------------------------- */
948 tree_move_end (WTree
* tree
)
950 tree_move_to_bottom (tree
);
955 /* --------------------------------------------------------------------------------------------- */
958 tree_move_pgup (WTree
* tree
)
960 tree_move_backward (tree
, tlines (tree
) - 1);
965 /* --------------------------------------------------------------------------------------------- */
968 tree_move_pgdn (WTree
* tree
)
970 tree_move_forward (tree
, tlines (tree
) - 1);
975 /* --------------------------------------------------------------------------------------------- */
978 tree_move_left (WTree
* tree
)
982 if (tree_navigation_flag
)
984 v
= tree_move_to_parent (tree
);
992 /* --------------------------------------------------------------------------------------------- */
995 tree_move_right (WTree
* tree
)
999 if (tree_navigation_flag
)
1001 tree_move_to_child (tree
);
1010 /* --------------------------------------------------------------------------------------------- */
1013 tree_start_search (WTree
* tree
)
1017 if (tree
->searching
)
1019 if (tree
->selected_ptr
== tree
->store
->tree_last
)
1020 tree_move_to_top (tree
);
1023 /* set navigation mode temporarily to 'Static' because in
1024 * dynamic navigation mode tree_move_forward will not move
1025 * to a lower sublevel if necessary (sequent searches must
1026 * start with the directory followed the last found directory)
1028 i
= tree_navigation_flag
;
1029 tree_navigation_flag
= 0;
1030 tree_move_forward (tree
, 1);
1031 tree_navigation_flag
= i
;
1033 tree_do_search (tree
, 0);
1037 tree
->searching
= 1;
1038 tree
->search_buffer
[0] = 0;
1042 /* --------------------------------------------------------------------------------------------- */
1045 tree_toggle_navig (WTree
* tree
)
1047 tree_navigation_flag
= !tree_navigation_flag
;
1048 buttonbar_set_label (find_buttonbar (WIDGET (tree
)->owner
), 4,
1049 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1050 : Q_ ("ButtonBar|Dynamc"), tree_map
, WIDGET (tree
));
1053 /* --------------------------------------------------------------------------------------------- */
1056 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1058 cb_ret_t res
= MSG_HANDLED
;
1060 if (command
!= CK_Search
)
1061 tree
->searching
= 0;
1067 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1068 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1074 case CK_ToggleNavigation
:
1075 tree_toggle_navig (tree
);
1078 tree_copy (tree
, "");
1081 tree_move (tree
, "");
1084 tree_move_up (tree
);
1087 tree_move_down (tree
);
1090 tree_move_home (tree
);
1093 tree_move_end (tree
);
1096 tree_move_pgup (tree
);
1099 tree_move_pgdn (tree
);
1102 tree_chdir_sel (tree
);
1108 tree_start_search (tree
);
1114 if (!tree
->is_panel
)
1115 dlg_stop (WIDGET (tree
)->owner
);
1118 res
= MSG_NOT_HANDLED
;
1126 /* --------------------------------------------------------------------------------------------- */
1129 tree_key (WTree
* tree
, int key
)
1133 if (is_abort_char (key
))
1137 tree
->searching
= 0;
1139 return MSG_HANDLED
; /* eat abort char */
1141 /* modal tree dialog: let upper layer see the
1142 abort character and close the dialog */
1143 return MSG_NOT_HANDLED
;
1146 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1148 tree_do_search (tree
, key
);
1153 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1154 if (key
== tree_map
[i
].key
)
1155 switch (tree_map
[i
].command
)
1158 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1160 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1162 tree_execute_cmd (tree
, tree_map
[i
].command
);
1166 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1167 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1169 tree_start_search (tree
);
1170 tree_do_search (tree
, key
);
1174 return MSG_NOT_HANDLED
;
1177 /* --------------------------------------------------------------------------------------------- */
1180 tree_frame (WDialog
* h
, WTree
* tree
)
1182 Widget
*w
= WIDGET (tree
);
1184 tty_setcolor (NORMAL_COLOR
);
1188 const char *title
= _("Directory tree");
1189 const int len
= str_term_width1 (title
);
1191 draw_box (h
, w
->y
, w
->x
, w
->lines
, w
->cols
, FALSE
);
1193 widget_move (w
, 0, (w
->cols
- len
- 2) / 2);
1194 tty_printf (" %s ", title
);
1196 if (panels_options
.show_mini_info
)
1197 widget_move (w
, tlines (tree
) + 1, 0);
1198 tty_print_alt_char (ACS_LTEE
, FALSE
);
1199 widget_move (w
, tlines (tree
) + 1, w
->cols
- 1);
1200 tty_print_alt_char (ACS_RTEE
, FALSE
);
1201 tty_draw_hline (w
->y
+ tlines (tree
) + 1, w
->x
+ 1, ACS_HLINE
, w
->cols
- 2);
1205 /* --------------------------------------------------------------------------------------------- */
1208 tree_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1210 WTree
*tree
= (WTree
*) w
;
1211 WDialog
*h
= w
->owner
;
1212 WButtonBar
*b
= find_buttonbar (h
);
1217 tree_frame (h
, tree
);
1223 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, w
);
1224 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, w
);
1225 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, w
);
1226 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1227 : Q_ ("ButtonBar|Dynamc"), tree_map
, w
);
1228 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, w
);
1229 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, w
);
1231 /* FIXME: mkdir is currently defunct */
1232 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, w
);
1234 buttonbar_clear_label (b
, 7, WIDGET (tree
));
1236 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, w
);
1237 buttonbar_redraw (b
);
1239 /* FIXME: Should find a better way of only displaying the
1240 currently selected item */
1244 /* FIXME: Should find a better way of changing the color of the
1249 tree
->searching
= 0;
1254 return tree_key (tree
, parm
);
1257 /* command from buttonbar */
1258 return tree_execute_cmd (tree
, parm
);
1261 tree_destroy (tree
);
1265 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1269 /* --------------------------------------------------------------------------------------------- */
1270 /*** public functions ****************************************************************************/
1271 /* --------------------------------------------------------------------------------------------- */
1274 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1279 tree
= g_new (WTree
, 1);
1282 init_widget (w
, y
, x
, lines
, cols
, tree_callback
, tree_event
);
1283 tree
->is_panel
= is_panel
;
1284 tree
->selected_ptr
= 0;
1286 tree
->store
= tree_store_get ();
1287 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1288 tree
->tree_shown
= 0;
1289 tree
->search_buffer
[0] = 0;
1290 tree
->topdiff
= w
->lines
/ 2;
1291 tree
->searching
= 0;
1294 /* We do not want to keep the cursor */
1295 widget_want_cursor (w
, FALSE
);
1300 /* --------------------------------------------------------------------------------------------- */
1303 tree_chdir (WTree
* tree
, const char *dir
)
1306 tree_entry
*current
;
1308 vpath
= vfs_path_from_str (dir
);
1309 current
= tree_store_whereis (vpath
);
1310 if (current
!= NULL
)
1312 tree
->selected_ptr
= current
;
1313 tree_check_focus (tree
);
1315 vfs_path_free (vpath
);
1318 /* --------------------------------------------------------------------------------------------- */
1319 /** Return name of the currently selected entry */
1322 tree_selected_name (const WTree
* tree
)
1324 return tree
->selected_ptr
->name
;
1327 /* --------------------------------------------------------------------------------------------- */
1330 sync_tree (const char *path
)
1332 tree_chdir (the_tree
, path
);
1335 /* --------------------------------------------------------------------------------------------- */
1338 find_tree (struct WDialog
*h
)
1340 return (WTree
*) find_widget_type (h
, tree_callback
);
1343 /* --------------------------------------------------------------------------------------------- */