1 /* Directory tree browser for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
5 Written: 1994, 1996 Janne Kukonlehto
7 1996, 1999 Miguel de Icaza
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 This module has been converted to be a widget.
25 The program load and saves the tree each time the tree widget is
26 created and destroyed. This is required for the future vfs layer,
27 it will be possible to have tree views over virtual file systems.
32 * \brief Source: directory tree browser
40 #include <sys/types.h>
42 #include "lib/global.h"
44 #include "lib/tty/tty.h"
45 #include "lib/tty/mouse.h"
46 #include "lib/tty/key.h"
48 #include "lib/vfs/mc-vfs/vfs.h"
49 #include "lib/fileloc.h"
50 #include "lib/strutil.h"
52 #include "lib/widget.h"
54 #include "src/setup.h" /* confirm_delete */
55 #include "src/keybind-defaults.h"
56 #include "src/history.h"
60 #include "midnight.h" /* the_menubar */
61 #include "file.h" /* copy_dir_dir(), move_dir_dir(), erase_dir() */
62 #include "layout.h" /* command_prompt */
63 #include "treestore.h"
69 /*** global variables ****************************************************************************/
71 /* The pointer to the tree */
72 WTree
*the_tree
= NULL
;
74 /* If this is true, then when browsing the tree the other window will
75 * automatically reload it's directory with the contents of the currently
80 /*** file scope macro definitions ****************************************************************/
82 #define tlines(t) (t->is_panel ? t->widget.lines - 2 - (show_mini_info ? 2 : 0) : t->widget.lines)
84 /* Use the color of the parent widget for the unselected entries */
85 #define TREE_NORMALC(h) (h->color[DLG_COLOR_NORMAL])
86 #define TREE_CURRENTC(h) (h->color[DLG_COLOR_FOCUS])
88 /*** file scope type declarations ****************************************************************/
93 struct TreeStore
*store
;
94 tree_entry
*selected_ptr
; /* The selected directory */
95 char search_buffer
[MC_MAXFILENAMELEN
]; /* Current search string */
96 tree_entry
**tree_shown
; /* Entries currently on screen */
97 int is_panel
; /* panel or plain widget flag */
98 int active
; /* if it's currently selected */
99 int searching
; /* Are we on searching mode? */
100 int topdiff
; /* The difference between the topmost
101 shown and the selected */
104 /*** file scope variables ************************************************************************/
106 /* Specifies the display mode: 1d or 2d */
107 static gboolean tree_navigation_flag
= FALSE
;
109 /*** file scope functions ************************************************************************/
110 /* --------------------------------------------------------------------------------------------- */
112 static void tree_rescan (void *data
);
114 /* --------------------------------------------------------------------------------------------- */
117 back_ptr (tree_entry
* ptr
, int *count
)
121 while (ptr
&& ptr
->prev
&& i
< *count
)
130 /* --------------------------------------------------------------------------------------------- */
133 forw_ptr (tree_entry
* ptr
, int *count
)
137 while (ptr
&& ptr
->next
&& i
< *count
)
146 /* --------------------------------------------------------------------------------------------- */
149 remove_callback (tree_entry
* entry
, void *data
)
153 if (tree
->selected_ptr
== entry
)
155 if (tree
->selected_ptr
->next
)
156 tree
->selected_ptr
= tree
->selected_ptr
->next
;
158 tree
->selected_ptr
= tree
->selected_ptr
->prev
;
162 /* --------------------------------------------------------------------------------------------- */
163 /** Save the ~/.mc/Tree file */
166 save_tree (WTree
* tree
)
172 error
= tree_store_save ();
177 tree_name
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_TREESTORE_FILE
, (char *) NULL
);
178 fprintf (stderr
, _("Cannot open the %s file for writing:\n%s\n"), tree_name
,
179 unix_error_string (error
));
184 /* --------------------------------------------------------------------------------------------- */
187 tree_remove_entry (WTree
* tree
, char *name
)
190 tree_store_remove_entry (name
);
193 /* --------------------------------------------------------------------------------------------- */
196 tree_destroy (WTree
* tree
)
198 tree_store_remove_entry_remove_hook (remove_callback
);
201 g_free (tree
->tree_shown
);
202 tree
->tree_shown
= 0;
203 tree
->selected_ptr
= NULL
;
206 /* --------------------------------------------------------------------------------------------- */
207 /** Loads the .mc.tree file */
210 load_tree (WTree
* tree
)
214 tree
->selected_ptr
= tree
->store
->tree_first
;
215 tree_chdir (tree
, home_dir
);
218 /* --------------------------------------------------------------------------------------------- */
221 tree_show_mini_info (WTree
* tree
, int tree_lines
, int tree_cols
)
223 Dlg_head
*h
= tree
->widget
.owner
;
231 line
= tree_lines
+ 2;
234 line
= tree_lines
+ 1;
238 /* Show search string */
239 tty_setcolor (INPUT_COLOR
);
240 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
241 widget_move (&tree
->widget
, line
, 1);
242 tty_print_char (PATH_SEP
);
243 tty_print_string (str_fit_to_term (tree
->search_buffer
, tree_cols
- 2, J_LEFT_FIT
));
244 tty_print_char (' ');
248 /* Show full name of selected directory */
249 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
250 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
251 widget_move (&tree
->widget
, line
, 1);
252 tty_print_string (str_fit_to_term (tree
->selected_ptr
->name
, tree_cols
, J_LEFT_FIT
));
256 /* --------------------------------------------------------------------------------------------- */
259 show_tree (WTree
* tree
)
261 Dlg_head
*h
= tree
->widget
.owner
;
263 int i
, j
, topsublevel
;
265 int tree_lines
, tree_cols
;
268 tree_lines
= tlines (tree
);
269 tree_cols
= tree
->widget
.cols
;
271 widget_move ((Widget
*) tree
, y
, x
);
278 g_free (tree
->tree_shown
);
279 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
281 if (tree
->store
->tree_first
)
282 topsublevel
= tree
->store
->tree_first
->sublevel
;
285 if (!tree
->selected_ptr
)
287 tree
->selected_ptr
= tree
->store
->tree_first
;
290 current
= tree
->selected_ptr
;
292 /* Calculate the directory which is to be shown on the topmost line */
293 if (!tree_navigation_flag
)
294 current
= back_ptr (current
, &tree
->topdiff
);
298 while (current
->prev
&& i
< tree
->topdiff
)
300 current
= current
->prev
;
301 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
303 if (strncmp (current
->name
, tree
->selected_ptr
->name
, strlen (current
->name
)) == 0)
306 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
308 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--);
309 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
312 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
313 && strlen (tree
->selected_ptr
->name
) > 1)
315 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
316 strlen (tree
->selected_ptr
->name
)) == 0)
323 /* Loop for every line */
324 for (i
= 0; i
< tree_lines
; i
++)
326 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
328 /* Move to the beginning of the line */
329 tty_draw_hline (tree
->widget
.y
+ y
+ i
, tree
->widget
.x
+ x
, ' ', tree_cols
);
335 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
336 ? SELECTED_COLOR
: NORMAL_COLOR
);
338 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
340 tree
->tree_shown
[i
] = current
;
341 if (current
->sublevel
== topsublevel
)
344 tty_print_string (str_fit_to_term
345 (current
->name
, tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
349 /* Sub level directory */
350 tty_set_alt_charset (TRUE
);
352 /* Output branch parts */
353 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
355 if (tree_cols
- 8 - 3 * j
< 9)
357 tty_print_char (' ');
358 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
359 tty_print_char (ACS_VLINE
);
361 tty_print_char (' ');
362 tty_print_char (' ');
364 tty_print_char (' ');
366 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
367 tty_print_char (ACS_LLCORNER
);
369 tty_print_char (ACS_LTEE
);
370 tty_print_char (ACS_HLINE
);
371 tty_set_alt_charset (FALSE
);
374 tty_print_char (' ');
375 tty_print_string (str_fit_to_term
376 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
379 /* Calculate the next value for current */
380 current
= current
->next
;
381 if (tree_navigation_flag
)
383 while (current
!= NULL
)
385 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
387 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
388 strlen (current
->name
)) == 0)
391 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
393 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--)
395 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
398 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
399 && strlen (tree
->selected_ptr
->name
) > 1)
401 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
402 strlen (tree
->selected_ptr
->name
)) == 0)
405 current
= current
->next
;
410 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
413 /* --------------------------------------------------------------------------------------------- */
416 tree_check_focus (WTree
* tree
)
418 if (tree
->topdiff
< 3)
420 else if (tree
->topdiff
>= tlines (tree
) - 3)
421 tree
->topdiff
= tlines (tree
) - 3 - 1;
424 /* --------------------------------------------------------------------------------------------- */
427 tree_move_backward (WTree
* tree
, int i
)
429 if (!tree_navigation_flag
)
430 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
436 current
= tree
->selected_ptr
;
437 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
439 current
= current
->prev
;
440 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
442 tree
->selected_ptr
= current
;
450 tree_check_focus (tree
);
453 /* --------------------------------------------------------------------------------------------- */
456 tree_move_forward (WTree
* tree
, int i
)
458 if (!tree_navigation_flag
)
459 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
465 current
= tree
->selected_ptr
;
466 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
468 current
= current
->next
;
469 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
471 tree
->selected_ptr
= current
;
479 tree_check_focus (tree
);
482 /* --------------------------------------------------------------------------------------------- */
485 tree_move_to_child (WTree
* tree
)
489 /* Do we have a starting point? */
490 if (!tree
->selected_ptr
)
492 /* Take the next entry */
493 current
= tree
->selected_ptr
->next
;
494 /* Is it the child of the selected entry */
495 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
497 /* Yes -> select this entry */
498 tree
->selected_ptr
= current
;
500 tree_check_focus (tree
);
504 /* No -> rescan and try again */
506 current
= tree
->selected_ptr
->next
;
507 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
509 tree
->selected_ptr
= current
;
511 tree_check_focus (tree
);
516 /* --------------------------------------------------------------------------------------------- */
519 tree_move_to_parent (WTree
* tree
)
524 if (!tree
->selected_ptr
)
527 old
= tree
->selected_ptr
;
528 current
= tree
->selected_ptr
->prev
;
529 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
531 current
= current
->prev
;
535 current
= tree
->store
->tree_first
;
536 tree
->selected_ptr
= current
;
537 tree_check_focus (tree
);
538 return tree
->selected_ptr
!= old
;
541 /* --------------------------------------------------------------------------------------------- */
544 tree_move_to_top (WTree
* tree
)
546 tree
->selected_ptr
= tree
->store
->tree_first
;
550 /* --------------------------------------------------------------------------------------------- */
553 tree_move_to_bottom (WTree
* tree
)
555 tree
->selected_ptr
= tree
->store
->tree_last
;
556 tree
->topdiff
= tlines (tree
) - 3 - 1;
559 /* --------------------------------------------------------------------------------------------- */
560 /** Handle mouse click */
563 tree_event (WTree
* tree
, int y
)
565 if (tree
->tree_shown
[y
])
567 tree
->selected_ptr
= tree
->tree_shown
[y
];
573 /* --------------------------------------------------------------------------------------------- */
576 tree_chdir_sel (WTree
* tree
)
583 if (do_cd (tree
->selected_ptr
->name
, cd_exact
))
584 select_item (current_panel
);
586 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
587 tree
->selected_ptr
->name
, unix_error_string (errno
));
593 /* --------------------------------------------------------------------------------------------- */
596 maybe_chdir (WTree
* tree
)
598 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
599 tree_chdir_sel (tree
);
602 /* --------------------------------------------------------------------------------------------- */
603 /** Mouse callback */
606 event_callback (Gpm_Event
* event
, void *data
)
610 /* rest of the upper frame, the menu is invisible - call menu */
611 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) && event
->y
== 1 && !menubar_visible
)
613 event
->x
+= tree
->widget
.x
;
614 return the_menubar
->widget
.mouse (event
, the_menubar
);
617 if (!(event
->type
& GPM_UP
))
630 tree_move_backward (tree
, tlines (tree
) - 1);
633 else if (event
->y
>= tlines (tree
))
635 tree_move_forward (tree
, tlines (tree
) - 1);
640 tree_event (tree
, event
->y
);
641 if ((event
->type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
643 tree_chdir_sel (tree
);
649 /* --------------------------------------------------------------------------------------------- */
650 /** Search tree for text */
653 search_tree (WTree
* tree
, char *text
)
661 current
= tree
->selected_ptr
;
663 while (!wrapped
|| current
!= tree
->selected_ptr
)
665 if (strncmp (current
->subname
, text
, len
) == 0)
667 tree
->selected_ptr
= current
;
671 current
= current
->next
;
674 current
= tree
->store
->tree_first
;
679 tree_check_focus (tree
);
683 /* --------------------------------------------------------------------------------------------- */
686 tree_do_search (WTree
* tree
, int key
)
690 l
= strlen (tree
->search_buffer
);
691 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
692 tree
->search_buffer
[--l
] = '\0';
693 else if (key
&& l
< sizeof (tree
->search_buffer
))
695 tree
->search_buffer
[l
] = key
;
696 tree
->search_buffer
[++l
] = '\0';
699 if (!search_tree (tree
, tree
->search_buffer
))
700 tree
->search_buffer
[--l
] = 0;
706 /* --------------------------------------------------------------------------------------------- */
709 tree_rescan (void *data
)
711 char old_dir
[MC_MAXPATHLEN
];
715 if (tree
->selected_ptr
== NULL
|| mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
716 || mc_chdir (tree
->selected_ptr
->name
))
719 tree_store_rescan (tree
->selected_ptr
->name
);
720 ret
= mc_chdir (old_dir
);
723 /* --------------------------------------------------------------------------------------------- */
726 tree_forget (void *data
)
729 if (tree
->selected_ptr
)
730 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
733 /* --------------------------------------------------------------------------------------------- */
736 tree_copy (WTree
* tree
, const char *default_dest
)
738 char msg
[BUF_MEDIUM
];
741 if (tree
->selected_ptr
== NULL
)
744 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
745 str_trunc (tree
->selected_ptr
->name
, 50));
746 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
747 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
749 if (dest
!= NULL
&& *dest
!= '\0')
752 FileOpTotalContext
*tctx
;
754 ctx
= file_op_context_new (OP_COPY
);
755 tctx
= file_op_total_context_new ();
756 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
757 tctx
->ask_overwrite
= FALSE
;
758 tctx
->is_toplevel_file
= FALSE
;
759 copy_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
760 file_op_total_context_destroy (tctx
);
761 file_op_context_destroy (ctx
);
767 /* --------------------------------------------------------------------------------------------- */
770 tree_move (WTree
* tree
, const char *default_dest
)
772 char msg
[BUF_MEDIUM
];
776 FileOpTotalContext
*tctx
;
778 if (tree
->selected_ptr
== NULL
)
781 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
782 str_trunc (tree
->selected_ptr
->name
, 50));
784 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
786 if (dest
== NULL
|| *dest
== '\0')
792 if (stat (dest
, &buf
))
794 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
795 unix_error_string (errno
));
800 if (!S_ISDIR (buf
.st_mode
))
802 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
807 ctx
= file_op_context_new (OP_MOVE
);
808 tctx
= file_op_total_context_new ();
809 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
810 move_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
);
811 file_op_total_context_destroy (tctx
);
812 file_op_context_destroy (ctx
);
817 /* --------------------------------------------------------------------------------------------- */
821 tree_mkdir (WTree
* tree
)
823 char old_dir
[MC_MAXPATHLEN
];
825 if (!tree
->selected_ptr
)
827 if (mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
829 if (chdir (tree
->selected_ptr
->name
))
839 /* --------------------------------------------------------------------------------------------- */
842 tree_rmdir (void *data
)
846 FileOpTotalContext
*tctx
;
848 if (!tree
->selected_ptr
)
856 buf
= g_strdup_printf (_("Delete %s?"), tree
->selected_ptr
->name
);
857 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
863 ctx
= file_op_context_new (OP_DELETE
);
864 tctx
= file_op_total_context_new ();
866 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
867 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
869 file_op_total_context_destroy (tctx
);
870 file_op_context_destroy (ctx
);
873 /* --------------------------------------------------------------------------------------------- */
876 tree_move_up (WTree
* tree
)
878 tree_move_backward (tree
, 1);
883 /* --------------------------------------------------------------------------------------------- */
886 tree_move_down (WTree
* tree
)
888 tree_move_forward (tree
, 1);
893 /* --------------------------------------------------------------------------------------------- */
896 tree_move_home (WTree
* tree
)
898 tree_move_to_top (tree
);
903 /* --------------------------------------------------------------------------------------------- */
906 tree_move_end (WTree
* tree
)
908 tree_move_to_bottom (tree
);
913 /* --------------------------------------------------------------------------------------------- */
916 tree_move_pgup (WTree
* tree
)
918 tree_move_backward (tree
, tlines (tree
) - 1);
923 /* --------------------------------------------------------------------------------------------- */
926 tree_move_pgdn (WTree
* tree
)
928 tree_move_forward (tree
, tlines (tree
) - 1);
933 /* --------------------------------------------------------------------------------------------- */
936 tree_move_left (WTree
* tree
)
940 if (tree_navigation_flag
)
942 v
= tree_move_to_parent (tree
);
950 /* --------------------------------------------------------------------------------------------- */
953 tree_move_right (WTree
* tree
)
957 if (tree_navigation_flag
)
959 tree_move_to_child (tree
);
968 /* --------------------------------------------------------------------------------------------- */
971 tree_start_search (WTree
* tree
)
977 if (tree
->selected_ptr
== tree
->store
->tree_last
)
978 tree_move_to_top (tree
);
981 /* set navigation mode temporarily to 'Static' because in
982 * dynamic navigation mode tree_move_forward will not move
983 * to a lower sublevel if necessary (sequent searches must
984 * start with the directory followed the last found directory)
986 i
= tree_navigation_flag
;
987 tree_navigation_flag
= 0;
988 tree_move_forward (tree
, 1);
989 tree_navigation_flag
= i
;
991 tree_do_search (tree
, 0);
996 tree
->search_buffer
[0] = 0;
1000 /* --------------------------------------------------------------------------------------------- */
1003 tree_toggle_navig (WTree
* tree
)
1005 tree_navigation_flag
= !tree_navigation_flag
;
1006 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1007 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1008 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1011 /* --------------------------------------------------------------------------------------------- */
1014 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1016 cb_ret_t res
= MSG_HANDLED
;
1018 if (command
!= CK_TreeStartSearch
)
1019 tree
->searching
= 0;
1024 interactive_display (NULL
, "[Directory Tree]");
1029 case CK_TreeToggleNav
:
1030 tree_toggle_navig (tree
);
1033 tree_copy (tree
, "");
1036 tree_move (tree
, "");
1039 tree_move_up (tree
);
1041 case CK_TreeMoveDown
:
1042 tree_move_down (tree
);
1044 case CK_TreeMoveHome
:
1045 tree_move_home (tree
);
1047 case CK_TreeMoveEnd
:
1048 tree_move_end (tree
);
1050 case CK_TreeMovePgUp
:
1051 tree_move_pgup (tree
);
1053 case CK_TreeMovePgDn
:
1054 tree_move_pgdn (tree
);
1057 tree_chdir_sel (tree
);
1062 case CK_TreeStartSearch
:
1063 tree_start_search (tree
);
1069 res
= MSG_NOT_HANDLED
;
1077 /* --------------------------------------------------------------------------------------------- */
1080 tree_key (WTree
* tree
, int key
)
1084 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1085 if (key
== tree_map
[i
].key
)
1086 switch (tree_map
[i
].command
)
1088 case CK_TreeMoveLeft
:
1089 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1090 case CK_TreeMoveRight
:
1091 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1093 tree_execute_cmd (tree
, tree_map
[i
].command
);
1097 if (is_abort_char (key
))
1101 tree
->searching
= 0;
1103 return MSG_HANDLED
; /* eat abort char */
1105 /* modal tree dialog: let upper layer see the
1106 abort character and close the dialog */
1107 return MSG_NOT_HANDLED
;
1110 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1111 if ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
)
1113 if (tree
->searching
)
1115 tree_do_search (tree
, key
);
1120 if (!command_prompt
)
1122 tree_start_search (tree
);
1123 tree_do_search (tree
, key
);
1126 return tree
->is_panel
? MSG_HANDLED
: MSG_NOT_HANDLED
;
1129 return MSG_NOT_HANDLED
;
1132 /* --------------------------------------------------------------------------------------------- */
1135 tree_frame (Dlg_head
* h
, WTree
* tree
)
1137 tty_setcolor (NORMAL_COLOR
);
1138 widget_erase ((Widget
*) tree
);
1141 const char *title
= _("Directory tree");
1142 const int len
= str_term_width1 (title
);
1144 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1146 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1147 tty_printf (" %s ", title
);
1150 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1151 tty_print_alt_char (ACS_LTEE
, FALSE
);
1152 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1153 tty_print_alt_char (ACS_RTEE
, FALSE
);
1154 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1155 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1159 /* --------------------------------------------------------------------------------------------- */
1162 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1164 WTree
*tree
= (WTree
*) w
;
1165 Dlg_head
*h
= tree
->widget
.owner
;
1166 WButtonBar
*b
= find_buttonbar (h
);
1171 tree_frame (h
, tree
);
1177 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1178 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1179 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1180 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1181 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1182 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1183 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1185 /* FIXME: mkdir is currently defunct */
1186 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1188 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1190 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1191 buttonbar_redraw (b
);
1193 /* FIXME: Should find a better way of only displaying the
1194 currently selected item */
1198 /* FIXME: Should find a better way of changing the color of the
1201 case WIDGET_UNFOCUS
:
1203 tree
->searching
= 0;
1208 return tree_key (tree
, parm
);
1210 case WIDGET_COMMAND
:
1211 /* command from buttonbar */
1212 return tree_execute_cmd (tree
, parm
);
1214 case WIDGET_DESTROY
:
1215 tree_destroy (tree
);
1219 return default_proc (msg
, parm
);
1223 /* --------------------------------------------------------------------------------------------- */
1224 /*** public functions ****************************************************************************/
1225 /* --------------------------------------------------------------------------------------------- */
1228 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1230 WTree
*tree
= g_new (WTree
, 1);
1232 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1233 tree
->is_panel
= is_panel
;
1234 tree
->selected_ptr
= 0;
1236 tree
->store
= tree_store_get ();
1237 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1238 tree
->tree_shown
= 0;
1239 tree
->search_buffer
[0] = 0;
1240 tree
->topdiff
= tree
->widget
.lines
/ 2;
1241 tree
->searching
= 0;
1244 /* We do not want to keep the cursor */
1245 widget_want_cursor (tree
->widget
, 0);
1250 /* --------------------------------------------------------------------------------------------- */
1253 tree_chdir (WTree
* tree
, const char *dir
)
1255 tree_entry
*current
;
1257 current
= tree_store_whereis (dir
);
1259 if (current
!= NULL
)
1261 tree
->selected_ptr
= current
;
1262 tree_check_focus (tree
);
1266 /* --------------------------------------------------------------------------------------------- */
1267 /** Return name of the currently selected entry */
1270 tree_selected_name (const WTree
* tree
)
1272 return tree
->selected_ptr
->name
;
1275 /* --------------------------------------------------------------------------------------------- */
1278 sync_tree (const char *path
)
1280 tree_chdir (the_tree
, path
);
1283 /* --------------------------------------------------------------------------------------------- */
1286 find_tree (struct Dlg_head
*h
)
1288 return (WTree
*) find_widget_type (h
, tree_callback
);
1291 /* --------------------------------------------------------------------------------------------- */