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
,
789 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
791 if (dest
!= NULL
&& *dest
!= '\0')
794 FileOpTotalContext
*tctx
;
796 ctx
= file_op_context_new (OP_COPY
);
797 tctx
= file_op_total_context_new ();
798 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
799 tctx
->ask_overwrite
= FALSE
;
800 copy_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
801 file_op_total_context_destroy (tctx
);
802 file_op_context_destroy (ctx
);
806 g_free (selected_ptr_name
);
809 /* --------------------------------------------------------------------------------------------- */
812 tree_move (WTree
* tree
, const char *default_dest
)
814 char msg
[BUF_MEDIUM
];
815 char *dest
, *selected_ptr_name
;
818 FileOpTotalContext
*tctx
;
820 if (tree
->selected_ptr
== NULL
)
823 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
825 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
826 str_trunc (selected_ptr_name
, 50));
828 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
,
829 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
831 if (dest
== NULL
|| *dest
== '\0')
834 if (stat (dest
, &buf
))
836 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
837 unix_error_string (errno
));
841 if (!S_ISDIR (buf
.st_mode
))
843 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
847 ctx
= file_op_context_new (OP_MOVE
);
848 tctx
= file_op_total_context_new ();
849 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
850 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
851 file_op_total_context_destroy (tctx
);
852 file_op_context_destroy (ctx
);
855 g_free (selected_ptr_name
);
859 /* --------------------------------------------------------------------------------------------- */
863 tree_mkdir (WTree
* tree
)
865 char old_dir
[MC_MAXPATHLEN
];
867 if (!tree
->selected_ptr
)
869 if (chdir (tree
->selected_ptr
->name
))
879 /* --------------------------------------------------------------------------------------------- */
882 tree_rmdir (void *data
)
886 FileOpTotalContext
*tctx
;
888 if (!tree
->selected_ptr
)
895 char *selected_ptr_name
;
897 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
898 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
899 g_free (selected_ptr_name
);
901 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
907 ctx
= file_op_context_new (OP_DELETE
);
908 tctx
= file_op_total_context_new ();
910 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
911 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
913 file_op_total_context_destroy (tctx
);
914 file_op_context_destroy (ctx
);
917 /* --------------------------------------------------------------------------------------------- */
920 tree_move_up (WTree
* tree
)
922 tree_move_backward (tree
, 1);
927 /* --------------------------------------------------------------------------------------------- */
930 tree_move_down (WTree
* tree
)
932 tree_move_forward (tree
, 1);
937 /* --------------------------------------------------------------------------------------------- */
940 tree_move_home (WTree
* tree
)
942 tree_move_to_top (tree
);
947 /* --------------------------------------------------------------------------------------------- */
950 tree_move_end (WTree
* tree
)
952 tree_move_to_bottom (tree
);
957 /* --------------------------------------------------------------------------------------------- */
960 tree_move_pgup (WTree
* tree
)
962 tree_move_backward (tree
, tlines (tree
) - 1);
967 /* --------------------------------------------------------------------------------------------- */
970 tree_move_pgdn (WTree
* tree
)
972 tree_move_forward (tree
, tlines (tree
) - 1);
977 /* --------------------------------------------------------------------------------------------- */
980 tree_move_left (WTree
* tree
)
984 if (tree_navigation_flag
)
986 v
= tree_move_to_parent (tree
);
994 /* --------------------------------------------------------------------------------------------- */
997 tree_move_right (WTree
* tree
)
1001 if (tree_navigation_flag
)
1003 tree_move_to_child (tree
);
1012 /* --------------------------------------------------------------------------------------------- */
1015 tree_start_search (WTree
* tree
)
1019 if (tree
->searching
)
1021 if (tree
->selected_ptr
== tree
->store
->tree_last
)
1022 tree_move_to_top (tree
);
1025 /* set navigation mode temporarily to 'Static' because in
1026 * dynamic navigation mode tree_move_forward will not move
1027 * to a lower sublevel if necessary (sequent searches must
1028 * start with the directory followed the last found directory)
1030 i
= tree_navigation_flag
;
1031 tree_navigation_flag
= 0;
1032 tree_move_forward (tree
, 1);
1033 tree_navigation_flag
= i
;
1035 tree_do_search (tree
, 0);
1039 tree
->searching
= 1;
1040 tree
->search_buffer
[0] = 0;
1044 /* --------------------------------------------------------------------------------------------- */
1047 tree_toggle_navig (WTree
* tree
)
1049 tree_navigation_flag
= !tree_navigation_flag
;
1050 buttonbar_set_label (find_buttonbar (WIDGET (tree
)->owner
), 4,
1051 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1052 : Q_ ("ButtonBar|Dynamc"), tree_map
, WIDGET (tree
));
1055 /* --------------------------------------------------------------------------------------------- */
1058 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1060 cb_ret_t res
= MSG_HANDLED
;
1062 if (command
!= CK_Search
)
1063 tree
->searching
= 0;
1069 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1070 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1076 case CK_ToggleNavigation
:
1077 tree_toggle_navig (tree
);
1080 tree_copy (tree
, "");
1083 tree_move (tree
, "");
1086 tree_move_up (tree
);
1089 tree_move_down (tree
);
1092 tree_move_home (tree
);
1095 tree_move_end (tree
);
1098 tree_move_pgup (tree
);
1101 tree_move_pgdn (tree
);
1104 tree_chdir_sel (tree
);
1110 tree_start_search (tree
);
1116 if (!tree
->is_panel
)
1117 dlg_stop (WIDGET (tree
)->owner
);
1120 res
= MSG_NOT_HANDLED
;
1128 /* --------------------------------------------------------------------------------------------- */
1131 tree_key (WTree
* tree
, int key
)
1135 if (is_abort_char (key
))
1139 tree
->searching
= 0;
1141 return MSG_HANDLED
; /* eat abort char */
1143 /* modal tree dialog: let upper layer see the
1144 abort character and close the dialog */
1145 return MSG_NOT_HANDLED
;
1148 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1150 tree_do_search (tree
, key
);
1155 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1156 if (key
== tree_map
[i
].key
)
1157 switch (tree_map
[i
].command
)
1160 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1162 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1164 tree_execute_cmd (tree
, tree_map
[i
].command
);
1168 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1169 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1171 tree_start_search (tree
);
1172 tree_do_search (tree
, key
);
1176 return MSG_NOT_HANDLED
;
1179 /* --------------------------------------------------------------------------------------------- */
1182 tree_frame (WDialog
* h
, WTree
* tree
)
1184 Widget
*w
= WIDGET (tree
);
1186 tty_setcolor (NORMAL_COLOR
);
1190 const char *title
= _("Directory tree");
1191 const int len
= str_term_width1 (title
);
1193 draw_box (h
, w
->y
, w
->x
, w
->lines
, w
->cols
, FALSE
);
1195 widget_move (w
, 0, (w
->cols
- len
- 2) / 2);
1196 tty_printf (" %s ", title
);
1198 if (panels_options
.show_mini_info
)
1199 widget_move (w
, tlines (tree
) + 1, 0);
1200 tty_print_alt_char (ACS_LTEE
, FALSE
);
1201 widget_move (w
, tlines (tree
) + 1, w
->cols
- 1);
1202 tty_print_alt_char (ACS_RTEE
, FALSE
);
1203 tty_draw_hline (w
->y
+ tlines (tree
) + 1, w
->x
+ 1, ACS_HLINE
, w
->cols
- 2);
1207 /* --------------------------------------------------------------------------------------------- */
1210 tree_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1212 WTree
*tree
= (WTree
*) w
;
1213 WDialog
*h
= w
->owner
;
1214 WButtonBar
*b
= find_buttonbar (h
);
1219 tree_frame (h
, tree
);
1225 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, w
);
1226 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, w
);
1227 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, w
);
1228 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1229 : Q_ ("ButtonBar|Dynamc"), tree_map
, w
);
1230 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, w
);
1231 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, w
);
1233 /* FIXME: mkdir is currently defunct */
1234 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, w
);
1236 buttonbar_clear_label (b
, 7, WIDGET (tree
));
1238 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, w
);
1239 buttonbar_redraw (b
);
1241 /* FIXME: Should find a better way of only displaying the
1242 currently selected item */
1246 /* FIXME: Should find a better way of changing the color of the
1251 tree
->searching
= 0;
1256 return tree_key (tree
, parm
);
1259 /* command from buttonbar */
1260 return tree_execute_cmd (tree
, parm
);
1263 tree_destroy (tree
);
1267 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1271 /* --------------------------------------------------------------------------------------------- */
1272 /*** public functions ****************************************************************************/
1273 /* --------------------------------------------------------------------------------------------- */
1276 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1281 tree
= g_new (WTree
, 1);
1284 init_widget (w
, y
, x
, lines
, cols
, tree_callback
, tree_event
);
1285 tree
->is_panel
= is_panel
;
1286 tree
->selected_ptr
= 0;
1288 tree
->store
= tree_store_get ();
1289 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1290 tree
->tree_shown
= 0;
1291 tree
->search_buffer
[0] = 0;
1292 tree
->topdiff
= w
->lines
/ 2;
1293 tree
->searching
= 0;
1296 /* We do not want to keep the cursor */
1297 widget_want_cursor (w
, FALSE
);
1302 /* --------------------------------------------------------------------------------------------- */
1305 tree_chdir (WTree
* tree
, const char *dir
)
1308 tree_entry
*current
;
1310 vpath
= vfs_path_from_str (dir
);
1311 current
= tree_store_whereis (vpath
);
1312 if (current
!= NULL
)
1314 tree
->selected_ptr
= current
;
1315 tree_check_focus (tree
);
1317 vfs_path_free (vpath
);
1320 /* --------------------------------------------------------------------------------------------- */
1321 /** Return name of the currently selected entry */
1324 tree_selected_name (const WTree
* tree
)
1326 return tree
->selected_ptr
->name
;
1329 /* --------------------------------------------------------------------------------------------- */
1332 sync_tree (const char *path
)
1334 tree_chdir (the_tree
, path
);
1337 /* --------------------------------------------------------------------------------------------- */
1340 find_tree (struct WDialog
*h
)
1342 return (WTree
*) find_widget_type (h
, tree_callback
);
1345 /* --------------------------------------------------------------------------------------------- */