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-2016
10 Free Software Foundation, Inc.
13 Janne Kukonlehto, 1994, 1996
15 Miguel de Icaza, 1996, 1999
16 Slava Zanko <slavazanko@gmail.com>, 2013
17 Andrew Borodin <aborodin@vmail.ru>, 2013, 2014, 2016
19 This file is part of the Midnight Commander.
21 The Midnight Commander is free software: you can redistribute it
22 and/or modify it under the terms of the GNU General Public License as
23 published by the Free Software Foundation, either version 3 of the License,
24 or (at your option) any later version.
26 The Midnight Commander is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
31 You should have received a copy of the GNU General Public License
32 along with this program. If not, see <http://www.gnu.org/licenses/>.
36 * \brief Source: directory tree browser
44 #include <sys/types.h>
46 #include "lib/global.h"
48 #include "lib/tty/tty.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
)
175 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
)
220 tree
->selected_ptr
= tree
->store
->tree_first
;
221 vpath
= vfs_path_from_str (mc_config_get_home_dir ());
222 tree_chdir (tree
, vpath
);
223 vfs_path_free (vpath
);
226 /* --------------------------------------------------------------------------------------------- */
229 tree_show_mini_info (WTree
* tree
, int tree_lines
, int tree_cols
)
231 Widget
*w
= WIDGET (tree
);
237 if (!panels_options
.show_mini_info
)
239 line
= tree_lines
+ 2;
242 line
= tree_lines
+ 1;
246 /* Show search string */
247 tty_setcolor (INPUT_COLOR
);
248 tty_draw_hline (w
->y
+ line
, w
->x
+ 1, ' ', tree_cols
);
249 widget_move (w
, line
, 1);
250 tty_print_char (PATH_SEP
);
251 tty_print_string (str_fit_to_term (tree
->search_buffer
, tree_cols
- 2, J_LEFT_FIT
));
252 tty_print_char (' ');
256 /* Show full name of selected directory */
257 WDialog
*h
= w
->owner
;
259 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
260 tty_draw_hline (w
->y
+ line
, w
->x
+ 1, ' ', tree_cols
);
261 widget_move (w
, line
, 1);
262 tty_print_string (str_fit_to_term
263 (vfs_path_as_str (tree
->selected_ptr
->name
), tree_cols
, J_LEFT_FIT
));
267 /* --------------------------------------------------------------------------------------------- */
270 show_tree (WTree
* tree
)
272 Widget
*w
= WIDGET (tree
);
273 WDialog
*h
= w
->owner
;
275 int i
, j
, topsublevel
;
277 int tree_lines
, tree_cols
;
280 tree_lines
= tlines (tree
);
283 widget_move (w
, y
, x
);
290 g_free (tree
->tree_shown
);
291 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
293 if (tree
->store
->tree_first
)
294 topsublevel
= tree
->store
->tree_first
->sublevel
;
297 if (!tree
->selected_ptr
)
299 tree
->selected_ptr
= tree
->store
->tree_first
;
302 current
= tree
->selected_ptr
;
304 /* Calculate the directory which is to be shown on the topmost line */
305 if (!tree_navigation_flag
)
306 current
= back_ptr (current
, &tree
->topdiff
);
310 while (current
->prev
&& i
< tree
->topdiff
)
312 current
= current
->prev
;
314 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
316 if (vfs_path_equal (current
->name
, tree
->selected_ptr
->name
))
319 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
323 cname
= vfs_path_as_str (current
->name
);
324 for (j
= strlen (cname
) - 1; !IS_PATH_SEP (cname
[j
]); j
--)
326 if (vfs_path_equal_len (current
->name
, tree
->selected_ptr
->name
, j
))
329 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1)
331 j
= vfs_path_len (tree
->selected_ptr
->name
);
332 if (j
> 1 && vfs_path_equal_len (current
->name
, tree
->selected_ptr
->name
, j
))
339 /* Loop for every line */
340 for (i
= 0; i
< tree_lines
; i
++)
342 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
344 /* Move to the beginning of the line */
345 tty_draw_hline (w
->y
+ y
+ i
, w
->x
+ x
, ' ', tree_cols
);
351 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
352 ? SELECTED_COLOR
: NORMAL_COLOR
);
354 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
356 tree
->tree_shown
[i
] = current
;
357 if (current
->sublevel
== topsublevel
)
359 tty_print_string (str_fit_to_term
360 (vfs_path_as_str (current
->name
),
361 tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
364 /* Sub level directory */
365 tty_set_alt_charset (TRUE
);
367 /* Output branch parts */
368 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
370 if (tree_cols
- 8 - 3 * j
< 9)
372 tty_print_char (' ');
373 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
374 tty_print_char (ACS_VLINE
);
376 tty_print_char (' ');
377 tty_print_char (' ');
379 tty_print_char (' ');
381 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
382 tty_print_char (ACS_LLCORNER
);
384 tty_print_char (ACS_LTEE
);
385 tty_print_char (ACS_HLINE
);
386 tty_set_alt_charset (FALSE
);
389 tty_print_char (' ');
390 tty_print_string (str_fit_to_term
391 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
394 /* Calculate the next value for current */
395 current
= current
->next
;
396 if (tree_navigation_flag
)
398 while (current
!= NULL
)
400 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
402 if (vfs_path_equal_len (current
->name
, tree
->selected_ptr
->name
,
403 vfs_path_len (current
->name
)))
406 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
410 cname
= vfs_path_as_str (current
->name
);
411 for (j
= strlen (cname
) - 1; !IS_PATH_SEP (cname
[j
]); j
--)
413 if (vfs_path_equal_len (current
->name
, tree
->selected_ptr
->name
, j
))
416 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
417 && vfs_path_len (tree
->selected_ptr
->name
) > 1)
419 if (vfs_path_equal_len (current
->name
, tree
->selected_ptr
->name
,
420 vfs_path_len (tree
->selected_ptr
->name
)))
423 current
= current
->next
;
428 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
431 /* --------------------------------------------------------------------------------------------- */
434 tree_check_focus (WTree
* tree
)
436 if (tree
->topdiff
< 3)
438 else if (tree
->topdiff
>= tlines (tree
) - 3)
439 tree
->topdiff
= tlines (tree
) - 3 - 1;
442 /* --------------------------------------------------------------------------------------------- */
445 tree_move_backward (WTree
* tree
, int i
)
447 if (!tree_navigation_flag
)
448 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
454 current
= tree
->selected_ptr
;
455 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
457 current
= current
->prev
;
458 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
460 tree
->selected_ptr
= current
;
468 tree_check_focus (tree
);
471 /* --------------------------------------------------------------------------------------------- */
474 tree_move_forward (WTree
* tree
, int i
)
476 if (!tree_navigation_flag
)
477 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
483 current
= tree
->selected_ptr
;
484 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
486 current
= current
->next
;
487 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
489 tree
->selected_ptr
= current
;
497 tree_check_focus (tree
);
500 /* --------------------------------------------------------------------------------------------- */
503 tree_move_to_child (WTree
* tree
)
507 /* Do we have a starting point? */
508 if (!tree
->selected_ptr
)
510 /* Take the next entry */
511 current
= tree
->selected_ptr
->next
;
512 /* Is it the child of the selected entry */
513 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
515 /* Yes -> select this entry */
516 tree
->selected_ptr
= current
;
518 tree_check_focus (tree
);
522 /* No -> rescan and try again */
524 current
= tree
->selected_ptr
->next
;
525 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
527 tree
->selected_ptr
= current
;
529 tree_check_focus (tree
);
534 /* --------------------------------------------------------------------------------------------- */
537 tree_move_to_parent (WTree
* tree
)
542 if (!tree
->selected_ptr
)
545 old
= tree
->selected_ptr
;
546 current
= tree
->selected_ptr
->prev
;
547 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
549 current
= current
->prev
;
553 current
= tree
->store
->tree_first
;
554 tree
->selected_ptr
= current
;
555 tree_check_focus (tree
);
556 return tree
->selected_ptr
!= old
;
559 /* --------------------------------------------------------------------------------------------- */
562 tree_move_to_top (WTree
* tree
)
564 tree
->selected_ptr
= tree
->store
->tree_first
;
568 /* --------------------------------------------------------------------------------------------- */
571 tree_move_to_bottom (WTree
* tree
)
573 tree
->selected_ptr
= tree
->store
->tree_last
;
574 tree
->topdiff
= tlines (tree
) - 3 - 1;
577 /* --------------------------------------------------------------------------------------------- */
580 tree_chdir_sel (WTree
* tree
)
586 if (do_cd (tree
->selected_ptr
->name
, cd_exact
))
587 select_item (current_panel
);
589 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
590 vfs_path_as_str (tree
->selected_ptr
->name
), unix_error_string (errno
));
592 widget_redraw (WIDGET (current_panel
));
598 WDialog
*h
= WIDGET (tree
)->owner
;
600 h
->ret_value
= B_ENTER
;
605 /* --------------------------------------------------------------------------------------------- */
608 maybe_chdir (WTree
* tree
)
610 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
611 tree_chdir_sel (tree
);
614 /* --------------------------------------------------------------------------------------------- */
615 /** Search tree for text */
618 search_tree (WTree
* tree
, char *text
)
626 current
= tree
->selected_ptr
;
628 while (!wrapped
|| current
!= tree
->selected_ptr
)
630 if (strncmp (current
->subname
, text
, len
) == 0)
632 tree
->selected_ptr
= current
;
636 current
= current
->next
;
639 current
= tree
->store
->tree_first
;
644 tree_check_focus (tree
);
648 /* --------------------------------------------------------------------------------------------- */
651 tree_do_search (WTree
* tree
, int key
)
655 l
= strlen (tree
->search_buffer
);
656 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
657 tree
->search_buffer
[--l
] = '\0';
658 else if (key
&& l
< sizeof (tree
->search_buffer
))
660 tree
->search_buffer
[l
] = key
;
661 tree
->search_buffer
[++l
] = '\0';
664 if (!search_tree (tree
, tree
->search_buffer
))
665 tree
->search_buffer
[--l
] = 0;
671 /* --------------------------------------------------------------------------------------------- */
674 tree_rescan (void *data
)
677 vfs_path_t
*old_vpath
;
679 old_vpath
= vfs_path_clone (vfs_get_raw_current_dir ());
680 if (old_vpath
== NULL
)
683 if (tree
->selected_ptr
!= NULL
&& mc_chdir (tree
->selected_ptr
->name
) == 0)
687 tree_store_rescan (tree
->selected_ptr
->name
);
688 ret
= mc_chdir (old_vpath
);
691 vfs_path_free (old_vpath
);
694 /* --------------------------------------------------------------------------------------------- */
697 tree_forget (void *data
)
700 if (tree
->selected_ptr
)
701 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
704 /* --------------------------------------------------------------------------------------------- */
707 tree_copy (WTree
* tree
, const char *default_dest
)
709 char msg
[BUF_MEDIUM
];
712 if (tree
->selected_ptr
== NULL
)
715 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
716 str_trunc (vfs_path_as_str (tree
->selected_ptr
->name
), 50));
717 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
718 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
,
719 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
721 if (dest
!= NULL
&& *dest
!= '\0')
723 file_op_context_t
*ctx
;
724 file_op_total_context_t
*tctx
;
726 ctx
= file_op_context_new (OP_COPY
);
727 tctx
= file_op_total_context_new ();
728 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
729 tctx
->ask_overwrite
= FALSE
;
730 copy_dir_dir (tctx
, ctx
, vfs_path_as_str (tree
->selected_ptr
->name
), dest
, TRUE
, FALSE
,
732 file_op_total_context_destroy (tctx
);
733 file_op_context_destroy (ctx
);
739 /* --------------------------------------------------------------------------------------------- */
742 tree_move (WTree
* tree
, const char *default_dest
)
744 char msg
[BUF_MEDIUM
];
747 file_op_context_t
*ctx
;
748 file_op_total_context_t
*tctx
;
750 if (tree
->selected_ptr
== NULL
)
753 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
754 str_trunc (vfs_path_as_str (tree
->selected_ptr
->name
), 50));
756 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
,
757 INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_CD
);
759 if (dest
== NULL
|| *dest
== '\0')
762 if (stat (dest
, &buf
))
764 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
765 unix_error_string (errno
));
769 if (!S_ISDIR (buf
.st_mode
))
771 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
775 ctx
= file_op_context_new (OP_MOVE
);
776 tctx
= file_op_total_context_new ();
777 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
778 move_dir_dir (tctx
, ctx
, vfs_path_as_str (tree
->selected_ptr
->name
), dest
);
779 file_op_total_context_destroy (tctx
);
780 file_op_context_destroy (ctx
);
786 /* --------------------------------------------------------------------------------------------- */
790 tree_mkdir (WTree
* tree
)
792 char old_dir
[MC_MAXPATHLEN
];
794 if (!tree
->selected_ptr
)
796 if (chdir (tree
->selected_ptr
->name
))
806 /* --------------------------------------------------------------------------------------------- */
809 tree_rmdir (void *data
)
812 file_op_context_t
*ctx
;
813 file_op_total_context_t
*tctx
;
815 if (!tree
->selected_ptr
)
823 buf
= g_strdup_printf (_("Delete %s?"), vfs_path_as_str (tree
->selected_ptr
->name
));
825 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
831 ctx
= file_op_context_new (OP_DELETE
);
832 tctx
= file_op_total_context_new ();
834 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
835 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
837 file_op_total_context_destroy (tctx
);
838 file_op_context_destroy (ctx
);
841 /* --------------------------------------------------------------------------------------------- */
844 tree_move_up (WTree
* tree
)
846 tree_move_backward (tree
, 1);
851 /* --------------------------------------------------------------------------------------------- */
854 tree_move_down (WTree
* tree
)
856 tree_move_forward (tree
, 1);
861 /* --------------------------------------------------------------------------------------------- */
864 tree_move_home (WTree
* tree
)
866 tree_move_to_top (tree
);
871 /* --------------------------------------------------------------------------------------------- */
874 tree_move_end (WTree
* tree
)
876 tree_move_to_bottom (tree
);
881 /* --------------------------------------------------------------------------------------------- */
884 tree_move_pgup (WTree
* tree
)
886 tree_move_backward (tree
, tlines (tree
) - 1);
891 /* --------------------------------------------------------------------------------------------- */
894 tree_move_pgdn (WTree
* tree
)
896 tree_move_forward (tree
, tlines (tree
) - 1);
901 /* --------------------------------------------------------------------------------------------- */
904 tree_move_left (WTree
* tree
)
908 if (tree_navigation_flag
)
910 v
= tree_move_to_parent (tree
);
918 /* --------------------------------------------------------------------------------------------- */
921 tree_move_right (WTree
* tree
)
925 if (tree_navigation_flag
)
927 tree_move_to_child (tree
);
936 /* --------------------------------------------------------------------------------------------- */
939 tree_start_search (WTree
* tree
)
945 if (tree
->selected_ptr
== tree
->store
->tree_last
)
946 tree_move_to_top (tree
);
949 /* set navigation mode temporarily to 'Static' because in
950 * dynamic navigation mode tree_move_forward will not move
951 * to a lower sublevel if necessary (sequent searches must
952 * start with the directory followed the last found directory)
954 i
= tree_navigation_flag
;
955 tree_navigation_flag
= 0;
956 tree_move_forward (tree
, 1);
957 tree_navigation_flag
= i
;
959 tree_do_search (tree
, 0);
964 tree
->search_buffer
[0] = 0;
968 /* --------------------------------------------------------------------------------------------- */
971 tree_toggle_navig (WTree
* tree
)
973 tree_navigation_flag
= !tree_navigation_flag
;
974 buttonbar_set_label (find_buttonbar (WIDGET (tree
)->owner
), 4,
975 tree_navigation_flag
? Q_ ("ButtonBar|Static")
976 : Q_ ("ButtonBar|Dynamc"), tree_map
, WIDGET (tree
));
979 /* --------------------------------------------------------------------------------------------- */
982 tree_execute_cmd (WTree
* tree
, long command
)
984 cb_ret_t res
= MSG_HANDLED
;
986 if (command
!= CK_Search
)
993 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
994 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1000 case CK_ToggleNavigation
:
1001 tree_toggle_navig (tree
);
1004 tree_copy (tree
, "");
1007 tree_move (tree
, "");
1010 tree_move_up (tree
);
1013 tree_move_down (tree
);
1016 tree_move_home (tree
);
1019 tree_move_end (tree
);
1022 tree_move_pgup (tree
);
1025 tree_move_pgdn (tree
);
1028 tree_chdir_sel (tree
);
1034 tree_start_search (tree
);
1040 if (!tree
->is_panel
)
1041 dlg_stop (WIDGET (tree
)->owner
);
1044 res
= MSG_NOT_HANDLED
;
1052 /* --------------------------------------------------------------------------------------------- */
1055 tree_key (WTree
* tree
, int key
)
1059 if (is_abort_char (key
))
1063 tree
->searching
= 0;
1065 return MSG_HANDLED
; /* eat abort char */
1067 /* modal tree dialog: let upper layer see the
1068 abort character and close the dialog */
1069 return MSG_NOT_HANDLED
;
1072 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1074 tree_do_search (tree
, key
);
1079 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1080 if (key
== tree_map
[i
].key
)
1081 switch (tree_map
[i
].command
)
1084 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1086 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1088 tree_execute_cmd (tree
, tree_map
[i
].command
);
1092 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1093 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1095 tree_start_search (tree
);
1096 tree_do_search (tree
, key
);
1100 return MSG_NOT_HANDLED
;
1103 /* --------------------------------------------------------------------------------------------- */
1106 tree_frame (WDialog
* h
, WTree
* tree
)
1108 Widget
*w
= WIDGET (tree
);
1112 tty_setcolor (NORMAL_COLOR
);
1116 const char *title
= _("Directory tree");
1117 const int len
= str_term_width1 (title
);
1119 tty_draw_box (w
->y
, w
->x
, w
->lines
, w
->cols
, FALSE
);
1121 widget_move (w
, 0, (w
->cols
- len
- 2) / 2);
1122 tty_printf (" %s ", title
);
1124 if (panels_options
.show_mini_info
)
1129 widget_move (w
, y
, 0);
1130 tty_print_alt_char (ACS_LTEE
, FALSE
);
1131 widget_move (w
, y
, w
->cols
- 1);
1132 tty_print_alt_char (ACS_RTEE
, FALSE
);
1133 tty_draw_hline (w
->y
+ y
, w
->x
+ 1, ACS_HLINE
, w
->cols
- 2);
1138 /* --------------------------------------------------------------------------------------------- */
1141 tree_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1143 WTree
*tree
= (WTree
*) w
;
1144 WDialog
*h
= w
->owner
;
1145 WButtonBar
*b
= find_buttonbar (h
);
1150 tree_frame (h
, tree
);
1156 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, w
);
1157 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, w
);
1158 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, w
);
1159 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1160 : Q_ ("ButtonBar|Dynamc"), tree_map
, w
);
1161 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, w
);
1162 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, w
);
1164 /* FIXME: mkdir is currently defunct */
1165 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, w
);
1167 buttonbar_clear_label (b
, 7, WIDGET (tree
));
1169 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, w
);
1170 widget_redraw (WIDGET (b
));
1172 /* FIXME: Should find a better way of only displaying the
1173 currently selected item */
1177 /* FIXME: Should find a better way of changing the color of the
1182 tree
->searching
= 0;
1187 return tree_key (tree
, parm
);
1190 /* command from buttonbar */
1191 return tree_execute_cmd (tree
, parm
);
1194 tree_destroy (tree
);
1198 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1202 /* --------------------------------------------------------------------------------------------- */
1208 tree_mouse_callback (Widget
* w
, mouse_msg_t msg
, mouse_event_t
* event
)
1210 WTree
*tree
= (WTree
*) w
;
1219 case MSG_MOUSE_DOWN
:
1220 /* rest of the upper frame - call menu */
1221 if (tree
->is_panel
&& event
->y
== WIDGET (w
->owner
)->y
)
1223 /* return MOU_UNHANDLED */
1224 event
->result
.abort
= TRUE
;
1226 else if (!tree
->active
)
1230 case MSG_MOUSE_CLICK
:
1234 lines
= tlines (tree
);
1238 tree_move_backward (tree
, lines
- 1);
1241 else if (y
>= lines
)
1243 tree_move_forward (tree
, lines
- 1);
1246 else if ((event
->count
& GPM_DOUBLE
) != 0)
1248 if (tree
->tree_shown
[y
] != NULL
)
1250 tree
->selected_ptr
= tree
->tree_shown
[y
];
1254 tree_chdir_sel (tree
);
1259 case MSG_MOUSE_SCROLL_UP
:
1260 case MSG_MOUSE_SCROLL_DOWN
:
1261 /* TODO: Ticket #2218 */
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 widget_init (w
, y
, x
, lines
, cols
, tree_callback
, tree_mouse_callback
);
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 vfs_path_t
* dir
)
1305 tree_entry
*current
;
1307 current
= tree_store_whereis (dir
);
1308 if (current
!= NULL
)
1310 tree
->selected_ptr
= current
;
1311 tree_check_focus (tree
);
1315 /* --------------------------------------------------------------------------------------------- */
1316 /** Return name of the currently selected entry */
1319 tree_selected_name (const WTree
* tree
)
1321 return tree
->selected_ptr
->name
;
1324 /* --------------------------------------------------------------------------------------------- */
1327 sync_tree (const vfs_path_t
* vpath
)
1329 tree_chdir (the_tree
, vpath
);
1332 /* --------------------------------------------------------------------------------------------- */
1335 find_tree (WDialog
* h
)
1337 return (WTree
*) find_widget_type (h
, tree_callback
);
1340 /* --------------------------------------------------------------------------------------------- */