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 tctx
->is_toplevel_file
= FALSE
;
763 copy_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
, TRUE
, FALSE
, FALSE
, NULL
);
764 file_op_total_context_destroy (tctx
);
765 file_op_context_destroy (ctx
);
771 /* --------------------------------------------------------------------------------------------- */
774 tree_move (WTree
* tree
, const char *default_dest
)
776 char msg
[BUF_MEDIUM
];
780 FileOpTotalContext
*tctx
;
782 if (tree
->selected_ptr
== NULL
)
785 g_snprintf (msg
, sizeof (msg
), _("Move \"%s\" directory to:"),
786 str_trunc (tree
->selected_ptr
->name
, 50));
788 input_expand_dialog (Q_ ("DialogTitle|Move"), msg
, MC_HISTORY_FM_TREE_MOVE
, default_dest
);
790 if (dest
== NULL
|| *dest
== '\0')
796 if (stat (dest
, &buf
))
798 message (D_ERROR
, MSG_ERROR
, _("Cannot stat the destination\n%s"),
799 unix_error_string (errno
));
804 if (!S_ISDIR (buf
.st_mode
))
806 file_error (_("Destination \"%s\" must be a directory\n%s"), dest
);
811 ctx
= file_op_context_new (OP_MOVE
);
812 tctx
= file_op_total_context_new ();
813 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
814 move_dir_dir (tctx
, ctx
, tree
->selected_ptr
->name
, dest
);
815 file_op_total_context_destroy (tctx
);
816 file_op_context_destroy (ctx
);
821 /* --------------------------------------------------------------------------------------------- */
825 tree_mkdir (WTree
* tree
)
827 char old_dir
[MC_MAXPATHLEN
];
829 if (!tree
->selected_ptr
)
831 if (mc_get_current_wd (old_dir
, MC_MAXPATHLEN
) == NULL
)
833 if (chdir (tree
->selected_ptr
->name
))
843 /* --------------------------------------------------------------------------------------------- */
846 tree_rmdir (void *data
)
850 FileOpTotalContext
*tctx
;
852 if (!tree
->selected_ptr
)
860 buf
= g_strdup_printf (_("Delete %s?"), tree
->selected_ptr
->name
);
861 result
= query_dialog (Q_ ("DialogTitle|Delete"), buf
, D_ERROR
, 2, _("&Yes"), _("&No"));
867 ctx
= file_op_context_new (OP_DELETE
);
868 tctx
= file_op_total_context_new ();
870 file_op_context_create_ui (ctx
, FALSE
, FILEGUI_DIALOG_ONE_ITEM
);
871 if (erase_dir (tctx
, ctx
, tree
->selected_ptr
->name
) == FILE_CONT
)
873 file_op_total_context_destroy (tctx
);
874 file_op_context_destroy (ctx
);
877 /* --------------------------------------------------------------------------------------------- */
880 tree_move_up (WTree
* tree
)
882 tree_move_backward (tree
, 1);
887 /* --------------------------------------------------------------------------------------------- */
890 tree_move_down (WTree
* tree
)
892 tree_move_forward (tree
, 1);
897 /* --------------------------------------------------------------------------------------------- */
900 tree_move_home (WTree
* tree
)
902 tree_move_to_top (tree
);
907 /* --------------------------------------------------------------------------------------------- */
910 tree_move_end (WTree
* tree
)
912 tree_move_to_bottom (tree
);
917 /* --------------------------------------------------------------------------------------------- */
920 tree_move_pgup (WTree
* tree
)
922 tree_move_backward (tree
, tlines (tree
) - 1);
927 /* --------------------------------------------------------------------------------------------- */
930 tree_move_pgdn (WTree
* tree
)
932 tree_move_forward (tree
, tlines (tree
) - 1);
937 /* --------------------------------------------------------------------------------------------- */
940 tree_move_left (WTree
* tree
)
944 if (tree_navigation_flag
)
946 v
= tree_move_to_parent (tree
);
954 /* --------------------------------------------------------------------------------------------- */
957 tree_move_right (WTree
* tree
)
961 if (tree_navigation_flag
)
963 tree_move_to_child (tree
);
972 /* --------------------------------------------------------------------------------------------- */
975 tree_start_search (WTree
* tree
)
981 if (tree
->selected_ptr
== tree
->store
->tree_last
)
982 tree_move_to_top (tree
);
985 /* set navigation mode temporarily to 'Static' because in
986 * dynamic navigation mode tree_move_forward will not move
987 * to a lower sublevel if necessary (sequent searches must
988 * start with the directory followed the last found directory)
990 i
= tree_navigation_flag
;
991 tree_navigation_flag
= 0;
992 tree_move_forward (tree
, 1);
993 tree_navigation_flag
= i
;
995 tree_do_search (tree
, 0);
1000 tree
->search_buffer
[0] = 0;
1004 /* --------------------------------------------------------------------------------------------- */
1007 tree_toggle_navig (WTree
* tree
)
1009 tree_navigation_flag
= !tree_navigation_flag
;
1010 buttonbar_set_label (find_buttonbar (tree
->widget
.owner
), 4,
1011 tree_navigation_flag
? Q_ ("ButtonBar|Static")
1012 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1015 /* --------------------------------------------------------------------------------------------- */
1018 tree_execute_cmd (WTree
* tree
, unsigned long command
)
1020 cb_ret_t res
= MSG_HANDLED
;
1022 if (command
!= CK_Search
)
1023 tree
->searching
= 0;
1029 ev_help_t event_data
= { NULL
, "[Directory Tree]" };
1030 mc_event_raise (MCEVENT_GROUP_CORE
, "help", &event_data
);
1036 case CK_ToggleNavigation
:
1037 tree_toggle_navig (tree
);
1040 tree_copy (tree
, "");
1043 tree_move (tree
, "");
1046 tree_move_up (tree
);
1049 tree_move_down (tree
);
1052 tree_move_home (tree
);
1055 tree_move_end (tree
);
1058 tree_move_pgup (tree
);
1061 tree_move_pgdn (tree
);
1064 tree_chdir_sel (tree
);
1070 tree_start_search (tree
);
1076 /* don't close tree due to SIGINT */
1079 res
= MSG_NOT_HANDLED
;
1087 /* --------------------------------------------------------------------------------------------- */
1090 tree_key (WTree
* tree
, int key
)
1094 if (is_abort_char (key
))
1098 tree
->searching
= 0;
1100 return MSG_HANDLED
; /* eat abort char */
1102 /* modal tree dialog: let upper layer see the
1103 abort character and close the dialog */
1104 return MSG_NOT_HANDLED
;
1107 if (tree
->searching
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1109 tree_do_search (tree
, key
);
1114 for (i
= 0; tree_map
[i
].key
!= 0; i
++)
1115 if (key
== tree_map
[i
].key
)
1116 switch (tree_map
[i
].command
)
1119 return tree_move_left (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1121 return tree_move_right (tree
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
1123 tree_execute_cmd (tree
, tree_map
[i
].command
);
1127 /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
1128 if (!command_prompt
&& ((key
>= ' ' && key
<= 255) || key
== KEY_BACKSPACE
))
1130 tree_start_search (tree
);
1131 tree_do_search (tree
, key
);
1135 return MSG_NOT_HANDLED
;
1138 /* --------------------------------------------------------------------------------------------- */
1141 tree_frame (Dlg_head
* h
, WTree
* tree
)
1143 tty_setcolor (NORMAL_COLOR
);
1144 widget_erase ((Widget
*) tree
);
1147 const char *title
= _("Directory tree");
1148 const int len
= str_term_width1 (title
);
1150 draw_box (h
, tree
->widget
.y
, tree
->widget
.x
, tree
->widget
.lines
, tree
->widget
.cols
, FALSE
);
1152 widget_move (&tree
->widget
, 0, (tree
->widget
.cols
- len
- 2) / 2);
1153 tty_printf (" %s ", title
);
1155 if (panels_options
.show_mini_info
)
1156 widget_move (&tree
->widget
, tlines (tree
) + 1, 0);
1157 tty_print_alt_char (ACS_LTEE
, FALSE
);
1158 widget_move (&tree
->widget
, tlines (tree
) + 1, tree
->widget
.cols
- 1);
1159 tty_print_alt_char (ACS_RTEE
, FALSE
);
1160 tty_draw_hline (tree
->widget
.y
+ tlines (tree
) + 1,
1161 tree
->widget
.x
+ 1, ACS_HLINE
, tree
->widget
.cols
- 2);
1165 /* --------------------------------------------------------------------------------------------- */
1168 tree_callback (Widget
* w
, widget_msg_t msg
, int parm
)
1170 WTree
*tree
= (WTree
*) w
;
1171 Dlg_head
*h
= tree
->widget
.owner
;
1172 WButtonBar
*b
= find_buttonbar (h
);
1177 tree_frame (h
, tree
);
1183 buttonbar_set_label (b
, 1, Q_ ("ButtonBar|Help"), tree_map
, (Widget
*) tree
);
1184 buttonbar_set_label (b
, 2, Q_ ("ButtonBar|Rescan"), tree_map
, (Widget
*) tree
);
1185 buttonbar_set_label (b
, 3, Q_ ("ButtonBar|Forget"), tree_map
, (Widget
*) tree
);
1186 buttonbar_set_label (b
, 4, tree_navigation_flag
? Q_ ("ButtonBar|Static")
1187 : Q_ ("ButtonBar|Dynamc"), tree_map
, (Widget
*) tree
);
1188 buttonbar_set_label (b
, 5, Q_ ("ButtonBar|Copy"), tree_map
, (Widget
*) tree
);
1189 buttonbar_set_label (b
, 6, Q_ ("ButtonBar|RenMov"), tree_map
, (Widget
*) tree
);
1191 /* FIXME: mkdir is currently defunct */
1192 buttonbar_set_label (b
, 7, Q_ ("ButtonBar|Mkdir"), tree_map
, (Widget
*) tree
);
1194 buttonbar_clear_label (b
, 7, (Widget
*) tree
);
1196 buttonbar_set_label (b
, 8, Q_ ("ButtonBar|Rmdir"), tree_map
, (Widget
*) tree
);
1197 buttonbar_redraw (b
);
1199 /* FIXME: Should find a better way of only displaying the
1200 currently selected item */
1204 /* FIXME: Should find a better way of changing the color of the
1207 case WIDGET_UNFOCUS
:
1209 tree
->searching
= 0;
1214 return tree_key (tree
, parm
);
1216 case WIDGET_COMMAND
:
1217 /* command from buttonbar */
1218 return tree_execute_cmd (tree
, parm
);
1220 case WIDGET_DESTROY
:
1221 tree_destroy (tree
);
1225 return default_proc (msg
, parm
);
1229 /* --------------------------------------------------------------------------------------------- */
1230 /*** public functions ****************************************************************************/
1231 /* --------------------------------------------------------------------------------------------- */
1234 tree_new (int y
, int x
, int lines
, int cols
, gboolean is_panel
)
1236 WTree
*tree
= g_new (WTree
, 1);
1238 init_widget (&tree
->widget
, y
, x
, lines
, cols
, tree_callback
, event_callback
);
1239 tree
->is_panel
= is_panel
;
1240 tree
->selected_ptr
= 0;
1242 tree
->store
= tree_store_get ();
1243 tree_store_add_entry_remove_hook (remove_callback
, tree
);
1244 tree
->tree_shown
= 0;
1245 tree
->search_buffer
[0] = 0;
1246 tree
->topdiff
= tree
->widget
.lines
/ 2;
1247 tree
->searching
= 0;
1250 /* We do not want to keep the cursor */
1251 widget_want_cursor (tree
->widget
, 0);
1256 /* --------------------------------------------------------------------------------------------- */
1259 tree_chdir (WTree
* tree
, const char *dir
)
1261 tree_entry
*current
;
1263 current
= tree_store_whereis (dir
);
1265 if (current
!= NULL
)
1267 tree
->selected_ptr
= current
;
1268 tree_check_focus (tree
);
1272 /* --------------------------------------------------------------------------------------------- */
1273 /** Return name of the currently selected entry */
1276 tree_selected_name (const WTree
* tree
)
1278 return tree
->selected_ptr
->name
;
1281 /* --------------------------------------------------------------------------------------------- */
1284 sync_tree (const char *path
)
1286 tree_chdir (the_tree
, path
);
1289 /* --------------------------------------------------------------------------------------------- */
1292 find_tree (struct Dlg_head
*h
)
1294 return (WTree
*) find_widget_type (h
, tree_callback
);
1297 /* --------------------------------------------------------------------------------------------- */