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, panels_options */
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 - (panels_options.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 ${XDG_CACHE_HOME}/mc/Tree file */
166 save_tree (WTree
* tree
)
172 error
= tree_store_save ();
178 g_build_filename (mc_config_get_cache_path (), MC_TREESTORE_FILE
, (char *) NULL
);
179 fprintf (stderr
, _("Cannot open the %s file for writing:\n%s\n"), tree_name
,
180 unix_error_string (error
));
185 /* --------------------------------------------------------------------------------------------- */
188 tree_remove_entry (WTree
* tree
, char *name
)
191 tree_store_remove_entry (name
);
194 /* --------------------------------------------------------------------------------------------- */
197 tree_destroy (WTree
* tree
)
199 tree_store_remove_entry_remove_hook (remove_callback
);
202 g_free (tree
->tree_shown
);
203 tree
->tree_shown
= 0;
204 tree
->selected_ptr
= NULL
;
207 /* --------------------------------------------------------------------------------------------- */
208 /** Loads the .mc.tree file */
211 load_tree (WTree
* tree
)
215 tree
->selected_ptr
= tree
->store
->tree_first
;
216 tree_chdir (tree
, mc_config_get_home_dir ());
219 /* --------------------------------------------------------------------------------------------- */
222 tree_show_mini_info (WTree
* tree
, int tree_lines
, int tree_cols
)
224 Dlg_head
*h
= tree
->widget
.owner
;
230 if (!panels_options
.show_mini_info
)
232 line
= tree_lines
+ 2;
235 line
= tree_lines
+ 1;
239 /* Show search string */
240 tty_setcolor (INPUT_COLOR
);
241 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
242 widget_move (&tree
->widget
, line
, 1);
243 tty_print_char (PATH_SEP
);
244 tty_print_string (str_fit_to_term (tree
->search_buffer
, tree_cols
- 2, J_LEFT_FIT
));
245 tty_print_char (' ');
249 /* Show full name of selected directory */
250 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
251 tty_draw_hline (tree
->widget
.y
+ line
, tree
->widget
.x
+ 1, ' ', tree_cols
);
252 widget_move (&tree
->widget
, line
, 1);
253 tty_print_string (str_fit_to_term (tree
->selected_ptr
->name
, tree_cols
, J_LEFT_FIT
));
257 /* --------------------------------------------------------------------------------------------- */
260 show_tree (WTree
* tree
)
262 Dlg_head
*h
= tree
->widget
.owner
;
264 int i
, j
, topsublevel
;
266 int tree_lines
, tree_cols
;
269 tree_lines
= tlines (tree
);
270 tree_cols
= tree
->widget
.cols
;
272 widget_move ((Widget
*) tree
, y
, x
);
279 g_free (tree
->tree_shown
);
280 tree
->tree_shown
= g_new0 (tree_entry
*, tree_lines
);
282 if (tree
->store
->tree_first
)
283 topsublevel
= tree
->store
->tree_first
->sublevel
;
286 if (!tree
->selected_ptr
)
288 tree
->selected_ptr
= tree
->store
->tree_first
;
291 current
= tree
->selected_ptr
;
293 /* Calculate the directory which is to be shown on the topmost line */
294 if (!tree_navigation_flag
)
295 current
= back_ptr (current
, &tree
->topdiff
);
299 while (current
->prev
&& i
< tree
->topdiff
)
301 current
= current
->prev
;
302 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
304 if (strncmp (current
->name
, tree
->selected_ptr
->name
, strlen (current
->name
)) == 0)
307 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
309 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--);
310 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
313 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
314 && strlen (tree
->selected_ptr
->name
) > 1)
316 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
317 strlen (tree
->selected_ptr
->name
)) == 0)
324 /* Loop for every line */
325 for (i
= 0; i
< tree_lines
; i
++)
327 tty_setcolor (tree
->is_panel
? NORMAL_COLOR
: TREE_NORMALC (h
));
329 /* Move to the beginning of the line */
330 tty_draw_hline (tree
->widget
.y
+ y
+ i
, tree
->widget
.x
+ x
, ' ', tree_cols
);
336 tty_setcolor (tree
->active
&& current
== tree
->selected_ptr
337 ? SELECTED_COLOR
: NORMAL_COLOR
);
339 tty_setcolor (current
== tree
->selected_ptr
? TREE_CURRENTC (h
) : TREE_NORMALC (h
));
341 tree
->tree_shown
[i
] = current
;
342 if (current
->sublevel
== topsublevel
)
345 tty_print_string (str_fit_to_term
346 (current
->name
, tree_cols
+ (tree
->is_panel
? 0 : 1), J_LEFT_FIT
));
350 /* Sub level directory */
351 tty_set_alt_charset (TRUE
);
353 /* Output branch parts */
354 for (j
= 0; j
< current
->sublevel
- topsublevel
- 1; j
++)
356 if (tree_cols
- 8 - 3 * j
< 9)
358 tty_print_char (' ');
359 if (current
->submask
& (1 << (j
+ topsublevel
+ 1)))
360 tty_print_char (ACS_VLINE
);
362 tty_print_char (' ');
363 tty_print_char (' ');
365 tty_print_char (' ');
367 if (!current
->next
|| !(current
->next
->submask
& (1 << current
->sublevel
)))
368 tty_print_char (ACS_LLCORNER
);
370 tty_print_char (ACS_LTEE
);
371 tty_print_char (ACS_HLINE
);
372 tty_set_alt_charset (FALSE
);
375 tty_print_char (' ');
376 tty_print_string (str_fit_to_term
377 (current
->subname
, tree_cols
- x
- 3 * j
, J_LEFT_FIT
));
380 /* Calculate the next value for current */
381 current
= current
->next
;
382 if (tree_navigation_flag
)
384 while (current
!= NULL
)
386 if (current
->sublevel
< tree
->selected_ptr
->sublevel
)
388 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
389 strlen (current
->name
)) == 0)
392 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
394 for (j
= strlen (current
->name
) - 1; current
->name
[j
] != PATH_SEP
; j
--)
396 if (strncmp (current
->name
, tree
->selected_ptr
->name
, j
) == 0)
399 else if (current
->sublevel
== tree
->selected_ptr
->sublevel
+ 1
400 && strlen (tree
->selected_ptr
->name
) > 1)
402 if (strncmp (current
->name
, tree
->selected_ptr
->name
,
403 strlen (tree
->selected_ptr
->name
)) == 0)
406 current
= current
->next
;
411 tree_show_mini_info (tree
, tree_lines
, tree_cols
);
414 /* --------------------------------------------------------------------------------------------- */
417 tree_check_focus (WTree
* tree
)
419 if (tree
->topdiff
< 3)
421 else if (tree
->topdiff
>= tlines (tree
) - 3)
422 tree
->topdiff
= tlines (tree
) - 3 - 1;
425 /* --------------------------------------------------------------------------------------------- */
428 tree_move_backward (WTree
* tree
, int i
)
430 if (!tree_navigation_flag
)
431 tree
->selected_ptr
= back_ptr (tree
->selected_ptr
, &i
);
437 current
= tree
->selected_ptr
;
438 while (j
< i
&& current
->prev
&& current
->prev
->sublevel
>= tree
->selected_ptr
->sublevel
)
440 current
= current
->prev
;
441 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
443 tree
->selected_ptr
= current
;
451 tree_check_focus (tree
);
454 /* --------------------------------------------------------------------------------------------- */
457 tree_move_forward (WTree
* tree
, int i
)
459 if (!tree_navigation_flag
)
460 tree
->selected_ptr
= forw_ptr (tree
->selected_ptr
, &i
);
466 current
= tree
->selected_ptr
;
467 while (j
< i
&& current
->next
&& current
->next
->sublevel
>= tree
->selected_ptr
->sublevel
)
469 current
= current
->next
;
470 if (current
->sublevel
== tree
->selected_ptr
->sublevel
)
472 tree
->selected_ptr
= current
;
480 tree_check_focus (tree
);
483 /* --------------------------------------------------------------------------------------------- */
486 tree_move_to_child (WTree
* tree
)
490 /* Do we have a starting point? */
491 if (!tree
->selected_ptr
)
493 /* Take the next entry */
494 current
= tree
->selected_ptr
->next
;
495 /* Is it the child of the selected entry */
496 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
498 /* Yes -> select this entry */
499 tree
->selected_ptr
= current
;
501 tree_check_focus (tree
);
505 /* No -> rescan and try again */
507 current
= tree
->selected_ptr
->next
;
508 if (current
&& current
->sublevel
> tree
->selected_ptr
->sublevel
)
510 tree
->selected_ptr
= current
;
512 tree_check_focus (tree
);
517 /* --------------------------------------------------------------------------------------------- */
520 tree_move_to_parent (WTree
* tree
)
525 if (!tree
->selected_ptr
)
528 old
= tree
->selected_ptr
;
529 current
= tree
->selected_ptr
->prev
;
530 while (current
&& current
->sublevel
>= tree
->selected_ptr
->sublevel
)
532 current
= current
->prev
;
536 current
= tree
->store
->tree_first
;
537 tree
->selected_ptr
= current
;
538 tree_check_focus (tree
);
539 return tree
->selected_ptr
!= old
;
542 /* --------------------------------------------------------------------------------------------- */
545 tree_move_to_top (WTree
* tree
)
547 tree
->selected_ptr
= tree
->store
->tree_first
;
551 /* --------------------------------------------------------------------------------------------- */
554 tree_move_to_bottom (WTree
* tree
)
556 tree
->selected_ptr
= tree
->store
->tree_last
;
557 tree
->topdiff
= tlines (tree
) - 3 - 1;
560 /* --------------------------------------------------------------------------------------------- */
561 /** Handle mouse click */
564 tree_event (WTree
* tree
, int y
)
566 if (tree
->tree_shown
[y
])
568 tree
->selected_ptr
= tree
->tree_shown
[y
];
574 /* --------------------------------------------------------------------------------------------- */
577 tree_chdir_sel (WTree
* tree
)
584 if (do_cd (tree
->selected_ptr
->name
, cd_exact
))
585 select_item (current_panel
);
587 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"),
588 tree
->selected_ptr
->name
, unix_error_string (errno
));
594 /* --------------------------------------------------------------------------------------------- */
597 maybe_chdir (WTree
* tree
)
599 if (xtree_mode
&& tree
->is_panel
&& is_idle ())
600 tree_chdir_sel (tree
);
603 /* --------------------------------------------------------------------------------------------- */
604 /** Mouse callback */
607 event_callback (Gpm_Event
* event
, void *data
)
611 /* rest of the upper frame, the menu is invisible - call menu */
612 if (tree
->is_panel
&& (event
->type
& GPM_DOWN
) && event
->y
== 1 && !menubar_visible
)
614 event
->x
+= tree
->widget
.x
;
615 return the_menubar
->widget
.mouse (event
, the_menubar
);
618 if (!(event
->type
& GPM_UP
))
631 tree_move_backward (tree
, tlines (tree
) - 1);
634 else if (event
->y
>= tlines (tree
))
636 tree_move_forward (tree
, tlines (tree
) - 1);
641 tree_event (tree
, event
->y
);
642 if ((event
->type
& (GPM_UP
| GPM_DOUBLE
)) == (GPM_UP
| GPM_DOUBLE
))
644 tree_chdir_sel (tree
);
650 /* --------------------------------------------------------------------------------------------- */
651 /** Search tree for text */
654 search_tree (WTree
* tree
, char *text
)
662 current
= tree
->selected_ptr
;
664 while (!wrapped
|| current
!= tree
->selected_ptr
)
666 if (strncmp (current
->subname
, text
, len
) == 0)
668 tree
->selected_ptr
= current
;
672 current
= current
->next
;
675 current
= tree
->store
->tree_first
;
680 tree_check_focus (tree
);
684 /* --------------------------------------------------------------------------------------------- */
687 tree_do_search (WTree
* tree
, int key
)
691 l
= strlen (tree
->search_buffer
);
692 if ((l
!= 0) && (key
== KEY_BACKSPACE
))
693 tree
->search_buffer
[--l
] = '\0';
694 else if (key
&& l
< sizeof (tree
->search_buffer
))
696 tree
->search_buffer
[l
] = key
;
697 tree
->search_buffer
[++l
] = '\0';
700 if (!search_tree (tree
, tree
->search_buffer
))
701 tree
->search_buffer
[--l
] = 0;
707 /* --------------------------------------------------------------------------------------------- */
710 tree_rescan (void *data
)
712 char old_dir
[MC_MAXPATHLEN
];
716 if (tree
->selected_ptr
== NULL
|| mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
717 || mc_chdir (tree
->selected_ptr
->name
))
720 tree_store_rescan (tree
->selected_ptr
->name
);
721 ret
= mc_chdir (old_dir
);
724 /* --------------------------------------------------------------------------------------------- */
727 tree_forget (void *data
)
730 if (tree
->selected_ptr
)
731 tree_remove_entry (tree
, tree
->selected_ptr
->name
);
734 /* --------------------------------------------------------------------------------------------- */
737 tree_copy (WTree
* tree
, const char *default_dest
)
739 char msg
[BUF_MEDIUM
];
742 if (tree
->selected_ptr
== NULL
)
745 g_snprintf (msg
, sizeof (msg
), _("Copy \"%s\" directory to:"),
746 str_trunc (tree
->selected_ptr
->name
, 50));
747 dest
= input_expand_dialog (Q_ ("DialogTitle|Copy"),
748 msg
, MC_HISTORY_FM_TREE_COPY
, default_dest
);
750 if (dest
!= NULL
&& *dest
!= '\0')
753 FileOpTotalContext
*tctx
;
755 ctx
= file_op_context_new (OP_COPY
);
756 tctx
= file_op_total_context_new ();
757 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_MULTI_ITEM
);
758 tctx
->ask_overwrite
= FALSE
;
759 tctx
->is_toplevel_file
= FALSE
;
760 copy_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
761 file_op_total_context_destroy (tctx
);
762 file_op_context_destroy (ctx
);
768 /* --------------------------------------------------------------------------------------------- */
771 tree_move (WTree
* tree
, const char *default_dest
)
773 char msg
[BUF_MEDIUM
];
777 FileOpTotalContext
*tctx
;
779 if (tree
->selected_ptr
== NULL
)
782 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
783 str_trunc (tree
->selected_ptr
->name
, 50));
785 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
787 if (dest
== NULL
|| *dest
== '\0')
793 if (stat (dest
, &buf
))
795 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
796 unix_error_string (errno
));
801 if (!S_ISDIR (buf
.st_mode
))
803 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
808 ctx
= file_op_context_new (OP_MOVE
);
809 tctx
= file_op_total_context_new ();
810 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
811 move_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
);
812 file_op_total_context_destroy (tctx
);
813 file_op_context_destroy (ctx
);
818 /* --------------------------------------------------------------------------------------------- */
822 tree_mkdir (WTree
* tree
)
824 char old_dir
[MC_MAXPATHLEN
];
826 if (!tree
->selected_ptr
)
828 if (mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
830 if (chdir (tree
->selected_ptr
->name
))
840 /* --------------------------------------------------------------------------------------------- */
843 tree_rmdir (void *data
)
847 FileOpTotalContext
*tctx
;
849 if (!tree
->selected_ptr
)
857 buf
= g_strdup_printf (_("Delete %s?"), tree
->selected_ptr
->name
);
858 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
864 ctx
= file_op_context_new (OP_DELETE
);
865 tctx
= file_op_total_context_new ();
867 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
868 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
870 file_op_total_context_destroy (tctx
);
871 file_op_context_destroy (ctx
);
874 /* --------------------------------------------------------------------------------------------- */
877 tree_move_up (WTree
* tree
)
879 tree_move_backward (tree
, 1);
884 /* --------------------------------------------------------------------------------------------- */
887 tree_move_down (WTree
* tree
)
889 tree_move_forward (tree
, 1);
894 /* --------------------------------------------------------------------------------------------- */
897 tree_move_home (WTree
* tree
)
899 tree_move_to_top (tree
);
904 /* --------------------------------------------------------------------------------------------- */
907 tree_move_end (WTree
* tree
)
909 tree_move_to_bottom (tree
);
914 /* --------------------------------------------------------------------------------------------- */
917 tree_move_pgup (WTree
* tree
)
919 tree_move_backward (tree
, tlines (tree
) - 1);
924 /* --------------------------------------------------------------------------------------------- */
927 tree_move_pgdn (WTree
* tree
)
929 tree_move_forward (tree
, tlines (tree
) - 1);
934 /* --------------------------------------------------------------------------------------------- */
937 tree_move_left (WTree
* tree
)
941 if (tree_navigation_flag
)
943 v
= tree_move_to_parent (tree
);
951 /* --------------------------------------------------------------------------------------------- */
954 tree_move_right (WTree
* tree
)
958 if (tree_navigation_flag
)
960 tree_move_to_child (tree
);
969 /* --------------------------------------------------------------------------------------------- */
972 tree_start_search (WTree
* tree
)
978 if (tree
->selected_ptr
== tree
->store
->tree_last
)
979 tree_move_to_top (tree
);
982 /* set navigation mode temporarily to 'Static' because in
983 * dynamic navigation mode tree_move_forward will not move
984 * to a lower sublevel if necessary (sequent searches must
985 * start with the directory followed the last found directory)
987 i
= tree_navigation_flag
;
988 tree_navigation_flag
= 0;
989 tree_move_forward (tree
, 1);
990 tree_navigation_flag
= i
;
992 tree_do_search (tree
, 0);
997 tree
->search_buffer
[0] = 0;
1001 /* --------------------------------------------------------------------------------------------- */
1004 tree_toggle_navig (WTree
* tree
)
1006 tree_navigation_flag
= !tree_navigation_flag
;
1007 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1008 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1009 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1012 /* --------------------------------------------------------------------------------------------- */
1015 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1017 cb_ret_t res
= MSG_HANDLED
;
1019 if (command
!= CK_TreeStartSearch
)
1020 tree
->searching
= 0;
1025 interactive_display (NULL
, "[Directory Tree]");
1030 case CK_TreeToggleNav
:
1031 tree_toggle_navig (tree
);
1034 tree_copy (tree
, "");
1037 tree_move (tree
, "");
1040 tree_move_up (tree
);
1042 case CK_TreeMoveDown
:
1043 tree_move_down (tree
);
1045 case CK_TreeMoveHome
:
1046 tree_move_home (tree
);
1048 case CK_TreeMoveEnd
:
1049 tree_move_end (tree
);
1051 case CK_TreeMovePgUp
:
1052 tree_move_pgup (tree
);
1054 case CK_TreeMovePgDn
:
1055 tree_move_pgdn (tree
);
1058 tree_chdir_sel (tree
);
1063 case CK_TreeStartSearch
:
1064 tree_start_search (tree
);
1070 res
= MSG_NOT_HANDLED
;
1078 /* --------------------------------------------------------------------------------------------- */
1081 tree_key (WTree
* tree
, int key
)
1085 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1086 if (key
== tree_map
[i
].key
)
1087 switch (tree_map
[i
].command
)
1089 case CK_TreeMoveLeft
:
1090 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1091 case CK_TreeMoveRight
:
1092 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1094 tree_execute_cmd (tree
, tree_map
[i
].command
);
1098 if (is_abort_char (key
))
1102 tree
->searching
= 0;
1104 return MSG_HANDLED
; /* eat abort char */
1106 /* modal tree dialog: let upper layer see the
1107 abort character and close the dialog */
1108 return MSG_NOT_HANDLED
;
1111 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1112 if ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
)
1114 if (tree
->searching
)
1116 tree_do_search (tree
, key
);
1121 if (!command_prompt
)
1123 tree_start_search (tree
);
1124 tree_do_search (tree
, key
);
1127 return tree
->is_panel
? MSG_HANDLED
: MSG_NOT_HANDLED
;
1130 return MSG_NOT_HANDLED
;
1133 /* --------------------------------------------------------------------------------------------- */
1136 tree_frame (Dlg_head
* h
, WTree
* tree
)
1138 tty_setcolor (NORMAL_COLOR
);
1139 widget_erase ((Widget
*) tree
);
1142 const char *title
= _("Directory tree");
1143 const int len
= str_term_width1 (title
);
1145 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1147 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1148 tty_printf (" %s ", title
);
1150 if (panels_options
.show_mini_info
)
1151 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1152 tty_print_alt_char (ACS_LTEE
, FALSE
);
1153 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1154 tty_print_alt_char (ACS_RTEE
, FALSE
);
1155 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1156 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1160 /* --------------------------------------------------------------------------------------------- */
1163 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1165 WTree
*tree
= (WTree
*) w
;
1166 Dlg_head
*h
= tree
->widget
.owner
;
1167 WButtonBar
*b
= find_buttonbar (h
);
1172 tree_frame (h
, tree
);
1178 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1179 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1180 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1181 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1182 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1183 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1184 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1186 /* FIXME: mkdir is currently defunct */
1187 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1189 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1191 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1192 buttonbar_redraw (b
);
1194 /* FIXME: Should find a better way of only displaying the
1195 currently selected item */
1199 /* FIXME: Should find a better way of changing the color of the
1202 case WIDGET_UNFOCUS
:
1204 tree
->searching
= 0;
1209 return tree_key (tree
, parm
);
1211 case WIDGET_COMMAND
:
1212 /* command from buttonbar */
1213 return tree_execute_cmd (tree
, parm
);
1215 case WIDGET_DESTROY
:
1216 tree_destroy (tree
);
1220 return default_proc (msg
, parm
);
1224 /* --------------------------------------------------------------------------------------------- */
1225 /*** public functions ****************************************************************************/
1226 /* --------------------------------------------------------------------------------------------- */
1229 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1231 WTree
*tree
= g_new (WTree
, 1);
1233 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1234 tree
->is_panel
= is_panel
;
1235 tree
->selected_ptr
= 0;
1237 tree
->store
= tree_store_get ();
1238 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1239 tree
->tree_shown
= 0;
1240 tree
->search_buffer
[0] = 0;
1241 tree
->topdiff
= tree
->widget
.lines
/ 2;
1242 tree
->searching
= 0;
1245 /* We do not want to keep the cursor */
1246 widget_want_cursor (tree
->widget
, 0);
1251 /* --------------------------------------------------------------------------------------------- */
1254 tree_chdir (WTree
* tree
, const char *dir
)
1256 tree_entry
*current
;
1258 current
= tree_store_whereis (dir
);
1260 if (current
!= NULL
)
1262 tree
->selected_ptr
= current
;
1263 tree_check_focus (tree
);
1267 /* --------------------------------------------------------------------------------------------- */
1268 /** Return name of the currently selected entry */
1271 tree_selected_name (const WTree
* tree
)
1273 return tree
->selected_ptr
->name
;
1276 /* --------------------------------------------------------------------------------------------- */
1279 sync_tree (const char *path
)
1281 tree_chdir (the_tree
, path
);
1284 /* --------------------------------------------------------------------------------------------- */
1287 find_tree (struct Dlg_head
*h
)
1289 return (WTree
*) find_widget_type (h
, tree_callback
);
1292 /* --------------------------------------------------------------------------------------------- */