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
)
746 vfs_path_t
*old_vpath
;
748 old_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
749 if (old_vpath
== NULL
)
752 if (tree
->selected_ptr
!= NULL
&& mc_chdir (tree
->selected_ptr
->name
) == 0)
754 tree_store_rescan (tree
->selected_ptr
->name
);
755 ret
= mc_chdir (old_vpath
);
757 vfs_path_free (old_vpath
);
760 /* --------------------------------------------------------------------------------------------- */
763 tree_forget (void *data
)
766 if (tree
->selected_ptr
)
767 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
770 /* --------------------------------------------------------------------------------------------- */
773 tree_copy (WTree
* tree
, const char *default_dest
)
775 char msg
[BUF_MEDIUM
];
776 char *dest
, *selected_ptr_name
;
778 if (tree
->selected_ptr
== NULL
)
781 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
783 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
784 str_trunc (selected_ptr_name
, 50));
785 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
786 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
788 if (dest
!= NULL
&& *dest
!= '\0')
791 FileOpTotalContext
*tctx
;
793 ctx
= file_op_context_new (OP_COPY
);
794 tctx
= file_op_total_context_new ();
795 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
796 tctx
->ask_overwrite
= FALSE
;
797 copy_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
798 file_op_total_context_destroy (tctx
);
799 file_op_context_destroy (ctx
);
803 g_free (selected_ptr_name
);
806 /* --------------------------------------------------------------------------------------------- */
809 tree_move (WTree
* tree
, const char *default_dest
)
811 char msg
[BUF_MEDIUM
];
812 char *dest
, *selected_ptr_name
;
815 FileOpTotalContext
*tctx
;
817 if (tree
->selected_ptr
== NULL
)
820 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
822 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
823 str_trunc (selected_ptr_name
, 50));
825 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
827 if (dest
== NULL
|| *dest
== '\0')
830 if (stat (dest
, &buf
))
832 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
833 unix_error_string (errno
));
837 if (!S_ISDIR (buf
.st_mode
))
839 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
843 ctx
= file_op_context_new (OP_MOVE
);
844 tctx
= file_op_total_context_new ();
845 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
846 move_dir_dir (tctx
, ctx
, selected_ptr_name
, dest
);
847 file_op_total_context_destroy (tctx
);
848 file_op_context_destroy (ctx
);
851 g_free (selected_ptr_name
);
855 /* --------------------------------------------------------------------------------------------- */
859 tree_mkdir (WTree
* tree
)
861 char old_dir
[MC_MAXPATHLEN
];
863 if (!tree
->selected_ptr
)
865 if (chdir (tree
->selected_ptr
->name
))
875 /* --------------------------------------------------------------------------------------------- */
878 tree_rmdir (void *data
)
882 FileOpTotalContext
*tctx
;
884 if (!tree
->selected_ptr
)
891 char *selected_ptr_name
;
893 selected_ptr_name
= vfs_path_to_str (tree
->selected_ptr
->name
);
894 buf
= g_strdup_printf (_("Delete %s?"), selected_ptr_name
);
895 g_free (selected_ptr_name
);
897 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
903 ctx
= file_op_context_new (OP_DELETE
);
904 tctx
= file_op_total_context_new ();
906 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
907 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
909 file_op_total_context_destroy (tctx
);
910 file_op_context_destroy (ctx
);
913 /* --------------------------------------------------------------------------------------------- */
916 tree_move_up (WTree
* tree
)
918 tree_move_backward (tree
, 1);
923 /* --------------------------------------------------------------------------------------------- */
926 tree_move_down (WTree
* tree
)
928 tree_move_forward (tree
, 1);
933 /* --------------------------------------------------------------------------------------------- */
936 tree_move_home (WTree
* tree
)
938 tree_move_to_top (tree
);
943 /* --------------------------------------------------------------------------------------------- */
946 tree_move_end (WTree
* tree
)
948 tree_move_to_bottom (tree
);
953 /* --------------------------------------------------------------------------------------------- */
956 tree_move_pgup (WTree
* tree
)
958 tree_move_backward (tree
, tlines (tree
) - 1);
963 /* --------------------------------------------------------------------------------------------- */
966 tree_move_pgdn (WTree
* tree
)
968 tree_move_forward (tree
, tlines (tree
) - 1);
973 /* --------------------------------------------------------------------------------------------- */
976 tree_move_left (WTree
* tree
)
980 if (tree_navigation_flag
)
982 v
= tree_move_to_parent (tree
);
990 /* --------------------------------------------------------------------------------------------- */
993 tree_move_right (WTree
* tree
)
997 if (tree_navigation_flag
)
999 tree_move_to_child (tree
);
1008 /* --------------------------------------------------------------------------------------------- */
1011 tree_start_search (WTree
* tree
)
1015 if (tree
->searching
)
1017 if (tree
->selected_ptr
== tree
->store
->tree_last
)
1018 tree_move_to_top (tree
);
1021 /* set navigation mode temporarily to 'Static' because in
1022 * dynamic navigation mode tree_move_forward will not move
1023 * to a lower sublevel if necessary (sequent searches must
1024 * start with the directory followed the last found directory)
1026 i
= tree_navigation_flag
;
1027 tree_navigation_flag
= 0;
1028 tree_move_forward (tree
, 1);
1029 tree_navigation_flag
= i
;
1031 tree_do_search (tree
, 0);
1035 tree
->searching
= 1;
1036 tree
->search_buffer
[0] = 0;
1040 /* --------------------------------------------------------------------------------------------- */
1043 tree_toggle_navig (WTree
* tree
)
1045 tree_navigation_flag
= !tree_navigation_flag
;
1046 buttonbar_set_label (find_buttonbar (WIDGET (tree
)->owner
), 4,
1047 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1048 : Q_ ("ButtonBar|Dynamc"), tree_map
, WIDGET (tree
));
1051 /* --------------------------------------------------------------------------------------------- */
1054 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1056 cb_ret_t res
= MSG_HANDLED
;
1058 if (command
!= CK_Search
)
1059 tree
->searching
= 0;
1065 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1066 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1072 case CK_ToggleNavigation
:
1073 tree_toggle_navig (tree
);
1076 tree_copy (tree
, "");
1079 tree_move (tree
, "");
1082 tree_move_up (tree
);
1085 tree_move_down (tree
);
1088 tree_move_home (tree
);
1091 tree_move_end (tree
);
1094 tree_move_pgup (tree
);
1097 tree_move_pgdn (tree
);
1100 tree_chdir_sel (tree
);
1106 tree_start_search (tree
);
1112 if (!tree
->is_panel
)
1113 dlg_stop (WIDGET (tree
)->owner
);
1116 res
= MSG_NOT_HANDLED
;
1124 /* --------------------------------------------------------------------------------------------- */
1127 tree_key (WTree
* tree
, int key
)
1131 if (is_abort_char (key
))
1135 tree
->searching
= 0;
1137 return MSG_HANDLED
; /* eat abort char */
1139 /* modal tree dialog: let upper layer see the
1140 abort character and close the dialog */
1141 return MSG_NOT_HANDLED
;
1144 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1146 tree_do_search (tree
, key
);
1151 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1152 if (key
== tree_map
[i
].key
)
1153 switch (tree_map
[i
].command
)
1156 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1158 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1160 tree_execute_cmd (tree
, tree_map
[i
].command
);
1164 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1165 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1167 tree_start_search (tree
);
1168 tree_do_search (tree
, key
);
1172 return MSG_NOT_HANDLED
;
1175 /* --------------------------------------------------------------------------------------------- */
1178 tree_frame (WDialog
* h
, WTree
* tree
)
1180 Widget
*w
= WIDGET (tree
);
1182 tty_setcolor (NORMAL_COLOR
);
1186 const char *title
= _("Directory tree");
1187 const int len
= str_term_width1 (title
);
1189 draw_box (h
, w
->y
, w
->x
, w
->lines
, w
->cols
, FALSE
);
1191 widget_move (w
, 0, (w
->cols
- len
- 2) / 2);
1192 tty_printf (" %s ", title
);
1194 if (panels_options
.show_mini_info
)
1195 widget_move (w
, tlines (tree
) + 1, 0);
1196 tty_print_alt_char (ACS_LTEE
, FALSE
);
1197 widget_move (w
, tlines (tree
) + 1, w
->cols
- 1);
1198 tty_print_alt_char (ACS_RTEE
, FALSE
);
1199 tty_draw_hline (w
->y
+ tlines (tree
) + 1, w
->x
+ 1, ACS_HLINE
, w
->cols
- 2);
1203 /* --------------------------------------------------------------------------------------------- */
1206 tree_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1208 WTree
*tree
= (WTree
*) w
;
1209 WDialog
*h
= w
->owner
;
1210 WButtonBar
*b
= find_buttonbar (h
);
1215 tree_frame (h
, tree
);
1221 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, w
);
1222 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, w
);
1223 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, w
);
1224 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1225 : Q_ ("ButtonBar|Dynamc"), tree_map
, w
);
1226 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, w
);
1227 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, w
);
1229 /* FIXME: mkdir is currently defunct */
1230 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, w
);
1232 buttonbar_clear_label (b
, 7, WIDGET (tree
));
1234 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, w
);
1235 buttonbar_redraw (b
);
1237 /* FIXME: Should find a better way of only displaying the
1238 currently selected item */
1242 /* FIXME: Should find a better way of changing the color of the
1247 tree
->searching
= 0;
1252 return tree_key (tree
, parm
);
1255 /* command from buttonbar */
1256 return tree_execute_cmd (tree
, parm
);
1259 tree_destroy (tree
);
1263 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1267 /* --------------------------------------------------------------------------------------------- */
1268 /*** public functions ****************************************************************************/
1269 /* --------------------------------------------------------------------------------------------- */
1272 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1277 tree
= g_new (WTree
, 1);
1280 init_widget (w
, y
, x
, lines
, cols
, tree_callback
, tree_event
);
1281 tree
->is_panel
= is_panel
;
1282 tree
->selected_ptr
= 0;
1284 tree
->store
= tree_store_get ();
1285 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1286 tree
->tree_shown
= 0;
1287 tree
->search_buffer
[0] = 0;
1288 tree
->topdiff
= w
->lines
/ 2;
1289 tree
->searching
= 0;
1292 /* We do not want to keep the cursor */
1293 widget_want_cursor (w
, FALSE
);
1298 /* --------------------------------------------------------------------------------------------- */
1301 tree_chdir (WTree
* tree
, const char *dir
)
1304 tree_entry
*current
;
1306 vpath
= vfs_path_from_str (dir
);
1307 current
= tree_store_whereis (vpath
);
1308 if (current
!= NULL
)
1310 tree
->selected_ptr
= current
;
1311 tree_check_focus (tree
);
1313 vfs_path_free (vpath
);
1316 /* --------------------------------------------------------------------------------------------- */
1317 /** Return name of the currently selected entry */
1320 tree_selected_name (const WTree
* tree
)
1322 return tree
->selected_ptr
->name
;
1325 /* --------------------------------------------------------------------------------------------- */
1328 sync_tree (const char *path
)
1330 tree_chdir (the_tree
, path
);
1333 /* --------------------------------------------------------------------------------------------- */
1336 find_tree (struct WDialog
*h
)
1338 return (WTree
*) find_widget_type (h
, tree_callback
);
1341 /* --------------------------------------------------------------------------------------------- */