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() */
59 #include "src/setup.h" /* confirm_delete, panels_options */
60 #include "src/keybind-defaults.h"
61 #include "src/history.h"
64 #include "midnight.h" /* the_menubar */
65 #include "file.h" /* copy_dir_dir(), move_dir_dir(), erase_dir() */
66 #include "layout.h" /* command_prompt */
67 #include "treestore.h"
73 /*** global variables ****************************************************************************/
75 /* The pointer to the tree */
76 WTree
*the_tree
= NULL
;
78 /* If this is true, then when browsing the tree the other window will
79 * automatically reload it's directory with the contents of the currently
84 /*** file scope macro definitions ****************************************************************/
86 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (panels_options.show_mini_info ? 2 : 0) : t->widget.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
, char *name
)
194 tree_store_remove_entry (name
);
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 Dlg_head
*h
= tree
->widget
.owner
;
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 (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
245 widget_move (&tree
->widget
, 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 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
254 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
255 widget_move (&tree
->widget
, line
, 1);
256 tty_print_string (str_fit_to_term (tree
->selected_ptr
->name
, tree_cols
, J_LEFT_FIT
));
260 /* --------------------------------------------------------------------------------------------- */
263 show_tree (WTree
* tree
)
265 Dlg_head
*h
= tree
->widget
.owner
;
267 int i
, j
, topsublevel
;
269 int tree_lines
, tree_cols
;
272 tree_lines
= tlines (tree
);
273 tree_cols
= tree
->widget
.cols
;
275 widget_move ((Widget
*) tree
, y
, x
);
282 g_free (tree
->tree_shown
);
283 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
285 if (tree
->store
->tree_first
)
286 topsublevel
= tree
->store
->tree_first
->sublevel
;
289 if (!tree
->selected_ptr
)
291 tree
->selected_ptr
= tree
->store
->tree_first
;
294 current
= tree
->selected_ptr
;
296 /* Calculate the directory which is to be shown on the topmost line */
297 if (!tree_navigation_flag
)
298 current
= back_ptr (current
, &tree
->topdiff
);
302 while (current
->prev
&& i
< tree
->topdiff
)
304 current
= current
->prev
;
305 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
307 if (strncmp (current
->name
, tree
->selected_ptr
->name
, strlen (current
->name
)) == 0)
310 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
312 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--);
313 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
316 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
317 && strlen (tree
->selected_ptr
->name
) > 1)
319 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
320 strlen (tree
->selected_ptr
->name
)) == 0)
327 /* Loop for every line */
328 for (i
= 0; i
< tree_lines
; i
++)
330 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
332 /* Move to the beginning of the line */
333 tty_draw_hline (tree
->widget
.y
+ y
+ i
, tree
->widget
.x
+ x
, ' ', tree_cols
);
339 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
340 ? SELECTED_COLOR
: NORMAL_COLOR
);
342 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
344 tree
->tree_shown
[i
] = current
;
345 if (current
->sublevel
== topsublevel
)
348 tty_print_string (str_fit_to_term
349 (current
->name
, tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
353 /* Sub level directory */
354 tty_set_alt_charset (TRUE
);
356 /* Output branch parts */
357 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
359 if (tree_cols
- 8 - 3 * j
< 9)
361 tty_print_char (' ');
362 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
363 tty_print_char (ACS_VLINE
);
365 tty_print_char (' ');
366 tty_print_char (' ');
368 tty_print_char (' ');
370 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
371 tty_print_char (ACS_LLCORNER
);
373 tty_print_char (ACS_LTEE
);
374 tty_print_char (ACS_HLINE
);
375 tty_set_alt_charset (FALSE
);
378 tty_print_char (' ');
379 tty_print_string (str_fit_to_term
380 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
383 /* Calculate the next value for current */
384 current
= current
->next
;
385 if (tree_navigation_flag
)
387 while (current
!= NULL
)
389 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
391 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
392 strlen (current
->name
)) == 0)
395 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
397 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--)
399 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
402 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
403 && strlen (tree
->selected_ptr
->name
) > 1)
405 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
406 strlen (tree
->selected_ptr
->name
)) == 0)
409 current
= current
->next
;
414 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
417 /* --------------------------------------------------------------------------------------------- */
420 tree_check_focus (WTree
* tree
)
422 if (tree
->topdiff
< 3)
424 else if (tree
->topdiff
>= tlines (tree
) - 3)
425 tree
->topdiff
= tlines (tree
) - 3 - 1;
428 /* --------------------------------------------------------------------------------------------- */
431 tree_move_backward (WTree
* tree
, int i
)
433 if (!tree_navigation_flag
)
434 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
440 current
= tree
->selected_ptr
;
441 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
443 current
= current
->prev
;
444 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
446 tree
->selected_ptr
= current
;
454 tree_check_focus (tree
);
457 /* --------------------------------------------------------------------------------------------- */
460 tree_move_forward (WTree
* tree
, int i
)
462 if (!tree_navigation_flag
)
463 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
469 current
= tree
->selected_ptr
;
470 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
472 current
= current
->next
;
473 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
475 tree
->selected_ptr
= current
;
483 tree_check_focus (tree
);
486 /* --------------------------------------------------------------------------------------------- */
489 tree_move_to_child (WTree
* tree
)
493 /* Do we have a starting point? */
494 if (!tree
->selected_ptr
)
496 /* Take the next entry */
497 current
= tree
->selected_ptr
->next
;
498 /* Is it the child of the selected entry */
499 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
501 /* Yes -> select this entry */
502 tree
->selected_ptr
= current
;
504 tree_check_focus (tree
);
508 /* No -> rescan and try again */
510 current
= tree
->selected_ptr
->next
;
511 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
513 tree
->selected_ptr
= current
;
515 tree_check_focus (tree
);
520 /* --------------------------------------------------------------------------------------------- */
523 tree_move_to_parent (WTree
* tree
)
528 if (!tree
->selected_ptr
)
531 old
= tree
->selected_ptr
;
532 current
= tree
->selected_ptr
->prev
;
533 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
535 current
= current
->prev
;
539 current
= tree
->store
->tree_first
;
540 tree
->selected_ptr
= current
;
541 tree_check_focus (tree
);
542 return tree
->selected_ptr
!= old
;
545 /* --------------------------------------------------------------------------------------------- */
548 tree_move_to_top (WTree
* tree
)
550 tree
->selected_ptr
= tree
->store
->tree_first
;
554 /* --------------------------------------------------------------------------------------------- */
557 tree_move_to_bottom (WTree
* tree
)
559 tree
->selected_ptr
= tree
->store
->tree_last
;
560 tree
->topdiff
= tlines (tree
) - 3 - 1;
563 /* --------------------------------------------------------------------------------------------- */
564 /** Handle mouse click */
567 tree_event (WTree
* tree
, int y
)
569 if (tree
->tree_shown
[y
])
571 tree
->selected_ptr
= tree
->tree_shown
[y
];
577 /* --------------------------------------------------------------------------------------------- */
580 tree_chdir_sel (WTree
* tree
)
587 if (do_cd (tree
->selected_ptr
->name
, cd_exact
))
588 select_item (current_panel
);
590 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
591 tree
->selected_ptr
->name
, unix_error_string (errno
));
597 /* --------------------------------------------------------------------------------------------- */
600 maybe_chdir (WTree
* tree
)
602 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
603 tree_chdir_sel (tree
);
606 /* --------------------------------------------------------------------------------------------- */
607 /** Mouse callback */
610 event_callback (Gpm_Event
* event
, void *data
)
614 /* rest of the upper frame, the menu is invisible - call menu */
615 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) && event
->y
== 1 && !menubar_visible
)
617 event
->x
+= tree
->widget
.x
;
618 return the_menubar
->widget
.mouse (event
, the_menubar
);
621 if (!(event
->type
& GPM_UP
))
634 tree_move_backward (tree
, tlines (tree
) - 1);
637 else if (event
->y
>= tlines (tree
))
639 tree_move_forward (tree
, tlines (tree
) - 1);
644 tree_event (tree
, event
->y
);
645 if ((event
->type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
647 tree_chdir_sel (tree
);
653 /* --------------------------------------------------------------------------------------------- */
654 /** Search tree for text */
657 search_tree (WTree
* tree
, char *text
)
665 current
= tree
->selected_ptr
;
667 while (!wrapped
|| current
!= tree
->selected_ptr
)
669 if (strncmp (current
->subname
, text
, len
) == 0)
671 tree
->selected_ptr
= current
;
675 current
= current
->next
;
678 current
= tree
->store
->tree_first
;
683 tree_check_focus (tree
);
687 /* --------------------------------------------------------------------------------------------- */
690 tree_do_search (WTree
* tree
, int key
)
694 l
= strlen (tree
->search_buffer
);
695 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
696 tree
->search_buffer
[--l
] = '\0';
697 else if (key
&& l
< sizeof (tree
->search_buffer
))
699 tree
->search_buffer
[l
] = key
;
700 tree
->search_buffer
[++l
] = '\0';
703 if (!search_tree (tree
, tree
->search_buffer
))
704 tree
->search_buffer
[--l
] = 0;
710 /* --------------------------------------------------------------------------------------------- */
713 tree_rescan (void *data
)
715 char old_dir
[MC_MAXPATHLEN
];
719 if (tree
->selected_ptr
== NULL
|| mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
720 || mc_chdir (tree
->selected_ptr
->name
))
723 tree_store_rescan (tree
->selected_ptr
->name
);
724 ret
= mc_chdir (old_dir
);
727 /* --------------------------------------------------------------------------------------------- */
730 tree_forget (void *data
)
733 if (tree
->selected_ptr
)
734 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
737 /* --------------------------------------------------------------------------------------------- */
740 tree_copy (WTree
* tree
, const char *default_dest
)
742 char msg
[BUF_MEDIUM
];
745 if (tree
->selected_ptr
== NULL
)
748 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
749 str_trunc (tree
->selected_ptr
->name
, 50));
750 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
751 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
753 if (dest
!= NULL
&& *dest
!= '\0')
756 FileOpTotalContext
*tctx
;
758 ctx
= file_op_context_new (OP_COPY
);
759 tctx
= file_op_total_context_new ();
760 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
761 tctx
->ask_overwrite
= FALSE
;
762 copy_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
763 file_op_total_context_destroy (tctx
);
764 file_op_context_destroy (ctx
);
770 /* --------------------------------------------------------------------------------------------- */
773 tree_move (WTree
* tree
, const char *default_dest
)
775 char msg
[BUF_MEDIUM
];
779 FileOpTotalContext
*tctx
;
781 if (tree
->selected_ptr
== NULL
)
784 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
785 str_trunc (tree
->selected_ptr
->name
, 50));
787 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
789 if (dest
== NULL
|| *dest
== '\0')
795 if (stat (dest
, &buf
))
797 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
798 unix_error_string (errno
));
803 if (!S_ISDIR (buf
.st_mode
))
805 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
810 ctx
= file_op_context_new (OP_MOVE
);
811 tctx
= file_op_total_context_new ();
812 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
813 move_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
);
814 file_op_total_context_destroy (tctx
);
815 file_op_context_destroy (ctx
);
820 /* --------------------------------------------------------------------------------------------- */
824 tree_mkdir (WTree
* tree
)
826 char old_dir
[MC_MAXPATHLEN
];
828 if (!tree
->selected_ptr
)
830 if (mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
832 if (chdir (tree
->selected_ptr
->name
))
842 /* --------------------------------------------------------------------------------------------- */
845 tree_rmdir (void *data
)
849 FileOpTotalContext
*tctx
;
851 if (!tree
->selected_ptr
)
859 buf
= g_strdup_printf (_("Delete %s?"), tree
->selected_ptr
->name
);
860 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
866 ctx
= file_op_context_new (OP_DELETE
);
867 tctx
= file_op_total_context_new ();
869 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
870 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
872 file_op_total_context_destroy (tctx
);
873 file_op_context_destroy (ctx
);
876 /* --------------------------------------------------------------------------------------------- */
879 tree_move_up (WTree
* tree
)
881 tree_move_backward (tree
, 1);
886 /* --------------------------------------------------------------------------------------------- */
889 tree_move_down (WTree
* tree
)
891 tree_move_forward (tree
, 1);
896 /* --------------------------------------------------------------------------------------------- */
899 tree_move_home (WTree
* tree
)
901 tree_move_to_top (tree
);
906 /* --------------------------------------------------------------------------------------------- */
909 tree_move_end (WTree
* tree
)
911 tree_move_to_bottom (tree
);
916 /* --------------------------------------------------------------------------------------------- */
919 tree_move_pgup (WTree
* tree
)
921 tree_move_backward (tree
, tlines (tree
) - 1);
926 /* --------------------------------------------------------------------------------------------- */
929 tree_move_pgdn (WTree
* tree
)
931 tree_move_forward (tree
, tlines (tree
) - 1);
936 /* --------------------------------------------------------------------------------------------- */
939 tree_move_left (WTree
* tree
)
943 if (tree_navigation_flag
)
945 v
= tree_move_to_parent (tree
);
953 /* --------------------------------------------------------------------------------------------- */
956 tree_move_right (WTree
* tree
)
960 if (tree_navigation_flag
)
962 tree_move_to_child (tree
);
971 /* --------------------------------------------------------------------------------------------- */
974 tree_start_search (WTree
* tree
)
980 if (tree
->selected_ptr
== tree
->store
->tree_last
)
981 tree_move_to_top (tree
);
984 /* set navigation mode temporarily to 'Static' because in
985 * dynamic navigation mode tree_move_forward will not move
986 * to a lower sublevel if necessary (sequent searches must
987 * start with the directory followed the last found directory)
989 i
= tree_navigation_flag
;
990 tree_navigation_flag
= 0;
991 tree_move_forward (tree
, 1);
992 tree_navigation_flag
= i
;
994 tree_do_search (tree
, 0);
999 tree
->search_buffer
[0] = 0;
1003 /* --------------------------------------------------------------------------------------------- */
1006 tree_toggle_navig (WTree
* tree
)
1008 tree_navigation_flag
= !tree_navigation_flag
;
1009 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1010 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1011 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1014 /* --------------------------------------------------------------------------------------------- */
1017 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1019 cb_ret_t res
= MSG_HANDLED
;
1021 if (command
!= CK_Search
)
1022 tree
->searching
= 0;
1028 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1029 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1035 case CK_ToggleNavigation
:
1036 tree_toggle_navig (tree
);
1039 tree_copy (tree
, "");
1042 tree_move (tree
, "");
1045 tree_move_up (tree
);
1048 tree_move_down (tree
);
1051 tree_move_home (tree
);
1054 tree_move_end (tree
);
1057 tree_move_pgup (tree
);
1060 tree_move_pgdn (tree
);
1063 tree_chdir_sel (tree
);
1069 tree_start_search (tree
);
1075 /* don't close tree due to SIGINT */
1078 res
= MSG_NOT_HANDLED
;
1086 /* --------------------------------------------------------------------------------------------- */
1089 tree_key (WTree
* tree
, int key
)
1093 if (is_abort_char (key
))
1097 tree
->searching
= 0;
1099 return MSG_HANDLED
; /* eat abort char */
1101 /* modal tree dialog: let upper layer see the
1102 abort character and close the dialog */
1103 return MSG_NOT_HANDLED
;
1106 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1108 tree_do_search (tree
, key
);
1113 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1114 if (key
== tree_map
[i
].key
)
1115 switch (tree_map
[i
].command
)
1118 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1120 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1122 tree_execute_cmd (tree
, tree_map
[i
].command
);
1126 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1127 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1129 tree_start_search (tree
);
1130 tree_do_search (tree
, key
);
1134 return MSG_NOT_HANDLED
;
1137 /* --------------------------------------------------------------------------------------------- */
1140 tree_frame (Dlg_head
* h
, WTree
* tree
)
1142 tty_setcolor (NORMAL_COLOR
);
1143 widget_erase ((Widget
*) tree
);
1146 const char *title
= _("Directory tree");
1147 const int len
= str_term_width1 (title
);
1149 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1151 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1152 tty_printf (" %s ", title
);
1154 if (panels_options
.show_mini_info
)
1155 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1156 tty_print_alt_char (ACS_LTEE
, FALSE
);
1157 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1158 tty_print_alt_char (ACS_RTEE
, FALSE
);
1159 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1160 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1164 /* --------------------------------------------------------------------------------------------- */
1167 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1169 WTree
*tree
= (WTree
*) w
;
1170 Dlg_head
*h
= tree
->widget
.owner
;
1171 WButtonBar
*b
= find_buttonbar (h
);
1176 tree_frame (h
, tree
);
1182 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1183 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1184 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1185 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1186 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1187 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1188 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1190 /* FIXME: mkdir is currently defunct */
1191 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1193 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1195 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1196 buttonbar_redraw (b
);
1198 /* FIXME: Should find a better way of only displaying the
1199 currently selected item */
1203 /* FIXME: Should find a better way of changing the color of the
1206 case WIDGET_UNFOCUS
:
1208 tree
->searching
= 0;
1213 return tree_key (tree
, parm
);
1215 case WIDGET_COMMAND
:
1216 /* command from buttonbar */
1217 return tree_execute_cmd (tree
, parm
);
1219 case WIDGET_DESTROY
:
1220 tree_destroy (tree
);
1224 return default_proc (msg
, parm
);
1228 /* --------------------------------------------------------------------------------------------- */
1229 /*** public functions ****************************************************************************/
1230 /* --------------------------------------------------------------------------------------------- */
1233 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1235 WTree
*tree
= g_new (WTree
, 1);
1237 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1238 tree
->is_panel
= is_panel
;
1239 tree
->selected_ptr
= 0;
1241 tree
->store
= tree_store_get ();
1242 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1243 tree
->tree_shown
= 0;
1244 tree
->search_buffer
[0] = 0;
1245 tree
->topdiff
= tree
->widget
.lines
/ 2;
1246 tree
->searching
= 0;
1249 /* We do not want to keep the cursor */
1250 widget_want_cursor (tree
->widget
, 0);
1255 /* --------------------------------------------------------------------------------------------- */
1258 tree_chdir (WTree
* tree
, const char *dir
)
1260 tree_entry
*current
;
1262 current
= tree_store_whereis (dir
);
1264 if (current
!= NULL
)
1266 tree
->selected_ptr
= current
;
1267 tree_check_focus (tree
);
1271 /* --------------------------------------------------------------------------------------------- */
1272 /** Return name of the currently selected entry */
1275 tree_selected_name (const WTree
* tree
)
1277 return tree
->selected_ptr
->name
;
1280 /* --------------------------------------------------------------------------------------------- */
1283 sync_tree (const char *path
)
1285 tree_chdir (the_tree
, path
);
1288 /* --------------------------------------------------------------------------------------------- */
1291 find_tree (struct Dlg_head
*h
)
1293 return (WTree
*) find_widget_type (h
, tree_callback
);
1296 /* --------------------------------------------------------------------------------------------- */