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
, INPUT_COMPLETE_DEFAULT
);
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
,
828 INPUT_COMPLETE_DEFAULT
);
830 if (dest
== NULL
|| *dest
== '\0')
833 if (stat (dest
, &buf
))
835 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
836 unix_error_string (errno
));
840 if (!S_ISDIR (buf
.st_mode
))
842 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
846 ctx
= file_op_context_new (OP_MOVE
);
847 tctx
= file_op_total_context_new ();
848 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
849 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
850 file_op_total_context_destroy (tctx
);
851 file_op_context_destroy (ctx
);
854 g_free (selected_ptr_name
);
858 /* --------------------------------------------------------------------------------------------- */
862 tree_mkdir (WTree
* tree
)
864 char old_dir
[MC_MAXPATHLEN
];
866 if (!tree
->selected_ptr
)
868 if (chdir (tree
->selected_ptr
->name
))
878 /* --------------------------------------------------------------------------------------------- */
881 tree_rmdir (void *data
)
885 FileOpTotalContext
*tctx
;
887 if (!tree
->selected_ptr
)
894 char *selected_ptr_name
;
896 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
897 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
898 g_free (selected_ptr_name
);
900 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
906 ctx
= file_op_context_new (OP_DELETE
);
907 tctx
= file_op_total_context_new ();
909 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
910 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
912 file_op_total_context_destroy (tctx
);
913 file_op_context_destroy (ctx
);
916 /* --------------------------------------------------------------------------------------------- */
919 tree_move_up (WTree
* tree
)
921 tree_move_backward (tree
, 1);
926 /* --------------------------------------------------------------------------------------------- */
929 tree_move_down (WTree
* tree
)
931 tree_move_forward (tree
, 1);
936 /* --------------------------------------------------------------------------------------------- */
939 tree_move_home (WTree
* tree
)
941 tree_move_to_top (tree
);
946 /* --------------------------------------------------------------------------------------------- */
949 tree_move_end (WTree
* tree
)
951 tree_move_to_bottom (tree
);
956 /* --------------------------------------------------------------------------------------------- */
959 tree_move_pgup (WTree
* tree
)
961 tree_move_backward (tree
, tlines (tree
) - 1);
966 /* --------------------------------------------------------------------------------------------- */
969 tree_move_pgdn (WTree
* tree
)
971 tree_move_forward (tree
, tlines (tree
) - 1);
976 /* --------------------------------------------------------------------------------------------- */
979 tree_move_left (WTree
* tree
)
983 if (tree_navigation_flag
)
985 v
= tree_move_to_parent (tree
);
993 /* --------------------------------------------------------------------------------------------- */
996 tree_move_right (WTree
* tree
)
1000 if (tree_navigation_flag
)
1002 tree_move_to_child (tree
);
1011 /* --------------------------------------------------------------------------------------------- */
1014 tree_start_search (WTree
* tree
)
1018 if (tree
->searching
)
1020 if (tree
->selected_ptr
== tree
->store
->tree_last
)
1021 tree_move_to_top (tree
);
1024 /* set navigation mode temporarily to 'Static' because in
1025 * dynamic navigation mode tree_move_forward will not move
1026 * to a lower sublevel if necessary (sequent searches must
1027 * start with the directory followed the last found directory)
1029 i
= tree_navigation_flag
;
1030 tree_navigation_flag
= 0;
1031 tree_move_forward (tree
, 1);
1032 tree_navigation_flag
= i
;
1034 tree_do_search (tree
, 0);
1038 tree
->searching
= 1;
1039 tree
->search_buffer
[0] = 0;
1043 /* --------------------------------------------------------------------------------------------- */
1046 tree_toggle_navig (WTree
* tree
)
1048 tree_navigation_flag
= !tree_navigation_flag
;
1049 buttonbar_set_label (find_buttonbar (WIDGET (tree
)->owner
), 4,
1050 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1051 : Q_ ("ButtonBar|Dynamc"), tree_map
, WIDGET (tree
));
1054 /* --------------------------------------------------------------------------------------------- */
1057 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1059 cb_ret_t res
= MSG_HANDLED
;
1061 if (command
!= CK_Search
)
1062 tree
->searching
= 0;
1068 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1069 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1075 case CK_ToggleNavigation
:
1076 tree_toggle_navig (tree
);
1079 tree_copy (tree
, "");
1082 tree_move (tree
, "");
1085 tree_move_up (tree
);
1088 tree_move_down (tree
);
1091 tree_move_home (tree
);
1094 tree_move_end (tree
);
1097 tree_move_pgup (tree
);
1100 tree_move_pgdn (tree
);
1103 tree_chdir_sel (tree
);
1109 tree_start_search (tree
);
1115 if (!tree
->is_panel
)
1116 dlg_stop (WIDGET (tree
)->owner
);
1119 res
= MSG_NOT_HANDLED
;
1127 /* --------------------------------------------------------------------------------------------- */
1130 tree_key (WTree
* tree
, int key
)
1134 if (is_abort_char (key
))
1138 tree
->searching
= 0;
1140 return MSG_HANDLED
; /* eat abort char */
1142 /* modal tree dialog: let upper layer see the
1143 abort character and close the dialog */
1144 return MSG_NOT_HANDLED
;
1147 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1149 tree_do_search (tree
, key
);
1154 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1155 if (key
== tree_map
[i
].key
)
1156 switch (tree_map
[i
].command
)
1159 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1161 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1163 tree_execute_cmd (tree
, tree_map
[i
].command
);
1167 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1168 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1170 tree_start_search (tree
);
1171 tree_do_search (tree
, key
);
1175 return MSG_NOT_HANDLED
;
1178 /* --------------------------------------------------------------------------------------------- */
1181 tree_frame (WDialog
* h
, WTree
* tree
)
1183 Widget
*w
= WIDGET (tree
);
1185 tty_setcolor (NORMAL_COLOR
);
1189 const char *title
= _("Directory tree");
1190 const int len
= str_term_width1 (title
);
1192 draw_box (h
, w
->y
, w
->x
, w
->lines
, w
->cols
, FALSE
);
1194 widget_move (w
, 0, (w
->cols
- len
- 2) / 2);
1195 tty_printf (" %s ", title
);
1197 if (panels_options
.show_mini_info
)
1198 widget_move (w
, tlines (tree
) + 1, 0);
1199 tty_print_alt_char (ACS_LTEE
, FALSE
);
1200 widget_move (w
, tlines (tree
) + 1, w
->cols
- 1);
1201 tty_print_alt_char (ACS_RTEE
, FALSE
);
1202 tty_draw_hline (w
->y
+ tlines (tree
) + 1, w
->x
+ 1, ACS_HLINE
, w
->cols
- 2);
1206 /* --------------------------------------------------------------------------------------------- */
1209 tree_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1211 WTree
*tree
= (WTree
*) w
;
1212 WDialog
*h
= w
->owner
;
1213 WButtonBar
*b
= find_buttonbar (h
);
1218 tree_frame (h
, tree
);
1224 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, w
);
1225 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, w
);
1226 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, w
);
1227 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1228 : Q_ ("ButtonBar|Dynamc"), tree_map
, w
);
1229 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, w
);
1230 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, w
);
1232 /* FIXME: mkdir is currently defunct */
1233 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, w
);
1235 buttonbar_clear_label (b
, 7, WIDGET (tree
));
1237 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, w
);
1238 buttonbar_redraw (b
);
1240 /* FIXME: Should find a better way of only displaying the
1241 currently selected item */
1245 /* FIXME: Should find a better way of changing the color of the
1250 tree
->searching
= 0;
1255 return tree_key (tree
, parm
);
1258 /* command from buttonbar */
1259 return tree_execute_cmd (tree
, parm
);
1262 tree_destroy (tree
);
1266 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1270 /* --------------------------------------------------------------------------------------------- */
1271 /*** public functions ****************************************************************************/
1272 /* --------------------------------------------------------------------------------------------- */
1275 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1280 tree
= g_new (WTree
, 1);
1283 init_widget (w
, y
, x
, lines
, cols
, tree_callback
, tree_event
);
1284 tree
->is_panel
= is_panel
;
1285 tree
->selected_ptr
= 0;
1287 tree
->store
= tree_store_get ();
1288 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1289 tree
->tree_shown
= 0;
1290 tree
->search_buffer
[0] = 0;
1291 tree
->topdiff
= w
->lines
/ 2;
1292 tree
->searching
= 0;
1295 /* We do not want to keep the cursor */
1296 widget_want_cursor (w
, FALSE
);
1301 /* --------------------------------------------------------------------------------------------- */
1304 tree_chdir (WTree
* tree
, const char *dir
)
1307 tree_entry
*current
;
1309 vpath
= vfs_path_from_str (dir
);
1310 current
= tree_store_whereis (vpath
);
1311 if (current
!= NULL
)
1313 tree
->selected_ptr
= current
;
1314 tree_check_focus (tree
);
1316 vfs_path_free (vpath
);
1319 /* --------------------------------------------------------------------------------------------- */
1320 /** Return name of the currently selected entry */
1323 tree_selected_name (const WTree
* tree
)
1325 return tree
->selected_ptr
->name
;
1328 /* --------------------------------------------------------------------------------------------- */
1331 sync_tree (const char *path
)
1333 tree_chdir (the_tree
, path
);
1336 /* --------------------------------------------------------------------------------------------- */
1339 find_tree (struct WDialog
*h
)
1341 return (WTree
*) find_widget_type (h
, tree_callback
);
1344 /* --------------------------------------------------------------------------------------------- */