Fix of DLG_ACTION handling in 'Configure options' dialog window.
[midnight-commander.git] / src / filemanager / tree.c
blob41a33a650188f3492c1482d46ceb9d49376de735
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
6 1997 Norbert Warmuth
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.
31 /** \file tree.c
32 * \brief Source: directory tree browser
35 #include <config.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
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"
47 #include "lib/skin.h"
48 #include "lib/vfs/mc-vfs/vfs.h"
49 #include "lib/fileloc.h"
50 #include "lib/strutil.h"
51 #include "lib/util.h"
52 #include "lib/widget.h"
54 #include "src/setup.h" /* confirm_delete */
55 #include "src/keybind-defaults.h"
56 #include "src/history.h"
57 #include "src/help.h"
59 #include "dir.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"
64 #include "cmd.h"
65 #include "filegui.h"
67 #include "tree.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
76 * selected directory.
78 int xtree_mode = 0;
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 ****************************************************************/
90 struct WTree
92 Widget widget;
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 /* --------------------------------------------------------------------------------------------- */
116 static tree_entry *
117 back_ptr (tree_entry * ptr, int *count)
119 int i = 0;
121 while (ptr && ptr->prev && i < *count)
123 ptr = ptr->prev;
124 i++;
126 *count = i;
127 return ptr;
130 /* --------------------------------------------------------------------------------------------- */
132 static tree_entry *
133 forw_ptr (tree_entry * ptr, int *count)
135 int i = 0;
137 while (ptr && ptr->next && i < *count)
139 ptr = ptr->next;
140 i++;
142 *count = i;
143 return ptr;
146 /* --------------------------------------------------------------------------------------------- */
148 static void
149 remove_callback (tree_entry * entry, void *data)
151 WTree *tree = data;
153 if (tree->selected_ptr == entry)
155 if (tree->selected_ptr->next)
156 tree->selected_ptr = tree->selected_ptr->next;
157 else
158 tree->selected_ptr = tree->selected_ptr->prev;
162 /* --------------------------------------------------------------------------------------------- */
163 /** Save the ~/.mc/Tree file */
165 static void
166 save_tree (WTree * tree)
168 int error;
169 char *tree_name;
171 (void) tree;
172 error = tree_store_save ();
175 if (error)
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));
180 g_free (tree_name);
184 /* --------------------------------------------------------------------------------------------- */
186 static void
187 tree_remove_entry (WTree * tree, char *name)
189 (void) tree;
190 tree_store_remove_entry (name);
193 /* --------------------------------------------------------------------------------------------- */
195 static void
196 tree_destroy (WTree * tree)
198 tree_store_remove_entry_remove_hook (remove_callback);
199 save_tree (tree);
201 g_free (tree->tree_shown);
202 tree->tree_shown = 0;
203 tree->selected_ptr = NULL;
206 /* --------------------------------------------------------------------------------------------- */
207 /** Loads the .mc.tree file */
209 static void
210 load_tree (WTree * tree)
212 tree_store_load ();
214 tree->selected_ptr = tree->store->tree_first;
215 tree_chdir (tree, home_dir);
218 /* --------------------------------------------------------------------------------------------- */
220 static void
221 tree_show_mini_info (WTree * tree, int tree_lines, int tree_cols)
223 Dlg_head *h = tree->widget.owner;
224 int line;
226 /* Show mini info */
227 if (tree->is_panel)
229 if (!show_mini_info)
230 return;
231 line = tree_lines + 2;
233 else
234 line = tree_lines + 1;
236 if (tree->searching)
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 (' ');
246 else
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 /* --------------------------------------------------------------------------------------------- */
258 static void
259 show_tree (WTree * tree)
261 Dlg_head *h = tree->widget.owner;
262 tree_entry *current;
263 int i, j, topsublevel;
264 int x = 0, y = 0;
265 int tree_lines, tree_cols;
267 /* Initialize */
268 tree_lines = tlines (tree);
269 tree_cols = tree->widget.cols;
271 widget_move ((Widget *) tree, y, x);
272 if (tree->is_panel)
274 tree_cols -= 2;
275 x = y = 1;
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;
283 else
284 topsublevel = 0;
285 if (!tree->selected_ptr)
287 tree->selected_ptr = tree->store->tree_first;
288 tree->topdiff = 0;
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);
295 else
297 i = 0;
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)
304 i++;
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)
310 i++;
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)
317 i++;
320 tree->topdiff = i;
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);
331 if (current == NULL)
332 continue;
334 if (tree->is_panel)
335 tty_setcolor (tree->active && current == tree->selected_ptr
336 ? SELECTED_COLOR : NORMAL_COLOR);
337 else
338 tty_setcolor (current == tree->selected_ptr ? TREE_CURRENTC (h) : TREE_NORMALC (h));
340 tree->tree_shown[i] = current;
341 if (current->sublevel == topsublevel)
343 /* Show full name */
344 tty_print_string (str_fit_to_term
345 (current->name, tree_cols + (tree->is_panel ? 0 : 1), J_LEFT_FIT));
347 else
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)
356 break;
357 tty_print_char (' ');
358 if (current->submask & (1 << (j + topsublevel + 1)))
359 tty_print_char (ACS_VLINE);
360 else
361 tty_print_char (' ');
362 tty_print_char (' ');
364 tty_print_char (' ');
365 j++;
366 if (!current->next || !(current->next->submask & (1 << current->sublevel)))
367 tty_print_char (ACS_LLCORNER);
368 else
369 tty_print_char (ACS_LTEE);
370 tty_print_char (ACS_HLINE);
371 tty_set_alt_charset (FALSE);
373 /* Show sub-name */
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)
389 break;
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)
396 break;
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)
403 break;
405 current = current->next;
410 tree_show_mini_info (tree, tree_lines, tree_cols);
413 /* --------------------------------------------------------------------------------------------- */
415 static void
416 tree_check_focus (WTree * tree)
418 if (tree->topdiff < 3)
419 tree->topdiff = 3;
420 else if (tree->topdiff >= tlines (tree) - 3)
421 tree->topdiff = tlines (tree) - 3 - 1;
424 /* --------------------------------------------------------------------------------------------- */
426 static void
427 tree_move_backward (WTree * tree, int i)
429 if (!tree_navigation_flag)
430 tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
431 else
433 tree_entry *current;
434 int j = 0;
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;
443 j++;
446 i = j;
449 tree->topdiff -= i;
450 tree_check_focus (tree);
453 /* --------------------------------------------------------------------------------------------- */
455 static void
456 tree_move_forward (WTree * tree, int i)
458 if (!tree_navigation_flag)
459 tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
460 else
462 tree_entry *current;
463 int j = 0;
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;
472 j++;
475 i = j;
478 tree->topdiff += i;
479 tree_check_focus (tree);
482 /* --------------------------------------------------------------------------------------------- */
484 static void
485 tree_move_to_child (WTree * tree)
487 tree_entry *current;
489 /* Do we have a starting point? */
490 if (!tree->selected_ptr)
491 return;
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;
499 tree->topdiff++;
500 tree_check_focus (tree);
502 else
504 /* No -> rescan and try again */
505 tree_rescan (tree);
506 current = tree->selected_ptr->next;
507 if (current && current->sublevel > tree->selected_ptr->sublevel)
509 tree->selected_ptr = current;
510 tree->topdiff++;
511 tree_check_focus (tree);
516 /* --------------------------------------------------------------------------------------------- */
518 static gboolean
519 tree_move_to_parent (WTree * tree)
521 tree_entry *current;
522 tree_entry *old;
524 if (!tree->selected_ptr)
525 return FALSE;
527 old = tree->selected_ptr;
528 current = tree->selected_ptr->prev;
529 while (current && current->sublevel >= tree->selected_ptr->sublevel)
531 current = current->prev;
532 tree->topdiff--;
534 if (!current)
535 current = tree->store->tree_first;
536 tree->selected_ptr = current;
537 tree_check_focus (tree);
538 return tree->selected_ptr != old;
541 /* --------------------------------------------------------------------------------------------- */
543 static void
544 tree_move_to_top (WTree * tree)
546 tree->selected_ptr = tree->store->tree_first;
547 tree->topdiff = 0;
550 /* --------------------------------------------------------------------------------------------- */
552 static void
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 */
562 static void
563 tree_event (WTree * tree, int y)
565 if (tree->tree_shown[y])
567 tree->selected_ptr = tree->tree_shown[y];
568 tree->topdiff = y;
570 show_tree (tree);
573 /* --------------------------------------------------------------------------------------------- */
575 static void
576 tree_chdir_sel (WTree * tree)
578 if (!tree->is_panel)
579 return;
581 change_panel ();
583 if (do_cd (tree->selected_ptr->name, cd_exact))
584 select_item (current_panel);
585 else
586 message (D_ERROR, MSG_ERROR, _("Cannot chdir to \"%s\"\n%s"),
587 tree->selected_ptr->name, unix_error_string (errno));
589 change_panel ();
590 show_tree (tree);
593 /* --------------------------------------------------------------------------------------------- */
595 static void
596 maybe_chdir (WTree * tree)
598 if (xtree_mode && tree->is_panel && is_idle ())
599 tree_chdir_sel (tree);
602 /* --------------------------------------------------------------------------------------------- */
603 /** Mouse callback */
605 static int
606 event_callback (Gpm_Event * event, void *data)
608 WTree *tree = 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))
618 return MOU_NORMAL;
620 if (tree->is_panel)
621 event->y--;
623 event->y--;
625 if (!tree->active)
626 change_panel ();
628 if (event->y < 0)
630 tree_move_backward (tree, tlines (tree) - 1);
631 show_tree (tree);
633 else if (event->y >= tlines (tree))
635 tree_move_forward (tree, tlines (tree) - 1);
636 show_tree (tree);
638 else
640 tree_event (tree, event->y);
641 if ((event->type & (GPM_UP | GPM_DOUBLE)) == (GPM_UP | GPM_DOUBLE))
643 tree_chdir_sel (tree);
646 return MOU_NORMAL;
649 /* --------------------------------------------------------------------------------------------- */
650 /** Search tree for text */
652 static int
653 search_tree (WTree * tree, char *text)
655 tree_entry *current;
656 int len;
657 int wrapped = 0;
658 int found = 0;
660 len = strlen (text);
661 current = tree->selected_ptr;
662 found = 0;
663 while (!wrapped || current != tree->selected_ptr)
665 if (strncmp (current->subname, text, len) == 0)
667 tree->selected_ptr = current;
668 found = 1;
669 break;
671 current = current->next;
672 if (!current)
674 current = tree->store->tree_first;
675 wrapped = 1;
677 tree->topdiff++;
679 tree_check_focus (tree);
680 return found;
683 /* --------------------------------------------------------------------------------------------- */
685 static void
686 tree_do_search (WTree * tree, int key)
688 size_t l;
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;
702 show_tree (tree);
703 maybe_chdir (tree);
706 /* --------------------------------------------------------------------------------------------- */
708 static void
709 tree_rescan (void *data)
711 char old_dir[MC_MAXPATHLEN];
712 WTree *tree = data;
713 int ret;
715 if (tree->selected_ptr == NULL || mc_get_current_wd (old_dir, MC_MAXPATHLEN) == NULL
716 || mc_chdir (tree->selected_ptr->name))
717 return;
719 tree_store_rescan (tree->selected_ptr->name);
720 ret = mc_chdir (old_dir);
723 /* --------------------------------------------------------------------------------------------- */
725 static void
726 tree_forget (void *data)
728 WTree *tree = data;
729 if (tree->selected_ptr)
730 tree_remove_entry (tree, tree->selected_ptr->name);
733 /* --------------------------------------------------------------------------------------------- */
735 static void
736 tree_copy (WTree * tree, const char *default_dest)
738 char msg[BUF_MEDIUM];
739 char *dest;
741 if (tree->selected_ptr == NULL)
742 return;
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')
751 FileOpContext *ctx;
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);
764 g_free (dest);
767 /* --------------------------------------------------------------------------------------------- */
769 static void
770 tree_move (WTree * tree, const char *default_dest)
772 char msg[BUF_MEDIUM];
773 char *dest;
774 struct stat buf;
775 FileOpContext *ctx;
776 FileOpTotalContext *tctx;
778 if (tree->selected_ptr == NULL)
779 return;
781 g_snprintf (msg, sizeof (msg), _("Move \"%s\" directory to:"),
782 str_trunc (tree->selected_ptr->name, 50));
783 dest =
784 input_expand_dialog (Q_ ("DialogTitle|Move"), msg, MC_HISTORY_FM_TREE_MOVE, default_dest);
786 if (dest == NULL || *dest == '\0')
788 g_free (dest);
789 return;
792 if (stat (dest, &buf))
794 message (D_ERROR, MSG_ERROR, _("Cannot stat the destination\n%s"),
795 unix_error_string (errno));
796 g_free (dest);
797 return;
800 if (!S_ISDIR (buf.st_mode))
802 file_error (_("Destination \"%s\" must be a directory\n%s"), dest);
803 g_free (dest);
804 return;
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);
814 g_free (dest);
817 /* --------------------------------------------------------------------------------------------- */
819 #if 0
820 static void
821 tree_mkdir (WTree * tree)
823 char old_dir[MC_MAXPATHLEN];
825 if (!tree->selected_ptr)
826 return;
827 if (mc_get_current_wd (old_dir, MC_MAXPATHLEN) == NULL)
828 return;
829 if (chdir (tree->selected_ptr->name))
830 return;
831 /* FIXME
832 mkdir_cmd (tree);
834 tree_rescan (tree);
835 chdir (old_dir);
837 #endif
839 /* --------------------------------------------------------------------------------------------- */
841 static void
842 tree_rmdir (void *data)
844 WTree *tree = data;
845 FileOpContext *ctx;
846 FileOpTotalContext *tctx;
848 if (!tree->selected_ptr)
849 return;
851 if (confirm_delete)
853 char *buf;
854 int result;
856 buf = g_strdup_printf (_("Delete %s?"), tree->selected_ptr->name);
857 result = query_dialog (Q_ ("DialogTitle|Delete"), buf, D_ERROR, 2, _("&Yes"), _("&No"));
858 g_free (buf);
859 if (result != 0)
860 return;
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)
868 tree_forget (tree);
869 file_op_total_context_destroy (tctx);
870 file_op_context_destroy (ctx);
873 /* --------------------------------------------------------------------------------------------- */
875 static inline void
876 tree_move_up (WTree * tree)
878 tree_move_backward (tree, 1);
879 show_tree (tree);
880 maybe_chdir (tree);
883 /* --------------------------------------------------------------------------------------------- */
885 static inline void
886 tree_move_down (WTree * tree)
888 tree_move_forward (tree, 1);
889 show_tree (tree);
890 maybe_chdir (tree);
893 /* --------------------------------------------------------------------------------------------- */
895 static inline void
896 tree_move_home (WTree * tree)
898 tree_move_to_top (tree);
899 show_tree (tree);
900 maybe_chdir (tree);
903 /* --------------------------------------------------------------------------------------------- */
905 static inline void
906 tree_move_end (WTree * tree)
908 tree_move_to_bottom (tree);
909 show_tree (tree);
910 maybe_chdir (tree);
913 /* --------------------------------------------------------------------------------------------- */
915 static void
916 tree_move_pgup (WTree * tree)
918 tree_move_backward (tree, tlines (tree) - 1);
919 show_tree (tree);
920 maybe_chdir (tree);
923 /* --------------------------------------------------------------------------------------------- */
925 static void
926 tree_move_pgdn (WTree * tree)
928 tree_move_forward (tree, tlines (tree) - 1);
929 show_tree (tree);
930 maybe_chdir (tree);
933 /* --------------------------------------------------------------------------------------------- */
935 static gboolean
936 tree_move_left (WTree * tree)
938 gboolean v = FALSE;
940 if (tree_navigation_flag)
942 v = tree_move_to_parent (tree);
943 show_tree (tree);
944 maybe_chdir (tree);
947 return v;
950 /* --------------------------------------------------------------------------------------------- */
952 static gboolean
953 tree_move_right (WTree * tree)
955 gboolean v = FALSE;
957 if (tree_navigation_flag)
959 tree_move_to_child (tree);
960 show_tree (tree);
961 maybe_chdir (tree);
962 v = TRUE;
965 return v;
968 /* --------------------------------------------------------------------------------------------- */
970 static void
971 tree_start_search (WTree * tree)
973 gboolean i;
975 if (tree->searching)
977 if (tree->selected_ptr == tree->store->tree_last)
978 tree_move_to_top (tree);
979 else
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);
993 else
995 tree->searching = 1;
996 tree->search_buffer[0] = 0;
1000 /* --------------------------------------------------------------------------------------------- */
1002 static void
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 /* --------------------------------------------------------------------------------------------- */
1013 static cb_ret_t
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;
1021 switch (command)
1023 case CK_TreeHelp:
1024 interactive_display (NULL, "[Directory Tree]");
1025 break;
1026 case CK_TreeForget:
1027 tree_forget (tree);
1028 break;
1029 case CK_TreeToggleNav:
1030 tree_toggle_navig (tree);
1031 break;
1032 case CK_TreeCopy:
1033 tree_copy (tree, "");
1034 break;
1035 case CK_TreeMove:
1036 tree_move (tree, "");
1037 break;
1038 case CK_TreeMoveUp:
1039 tree_move_up (tree);
1040 break;
1041 case CK_TreeMoveDown:
1042 tree_move_down (tree);
1043 break;
1044 case CK_TreeMoveHome:
1045 tree_move_home (tree);
1046 break;
1047 case CK_TreeMoveEnd:
1048 tree_move_end (tree);
1049 break;
1050 case CK_TreeMovePgUp:
1051 tree_move_pgup (tree);
1052 break;
1053 case CK_TreeMovePgDn:
1054 tree_move_pgdn (tree);
1055 break;
1056 case CK_TreeOpen:
1057 tree_chdir_sel (tree);
1058 break;
1059 case CK_TreeRescan:
1060 tree_rescan (tree);
1061 break;
1062 case CK_TreeStartSearch:
1063 tree_start_search (tree);
1064 break;
1065 case CK_TreeRemove:
1066 tree_rmdir (tree);
1067 break;
1068 default:
1069 res = MSG_NOT_HANDLED;
1072 show_tree (tree);
1074 return res;
1077 /* --------------------------------------------------------------------------------------------- */
1079 static cb_ret_t
1080 tree_key (WTree * tree, int key)
1082 size_t i;
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;
1092 default:
1093 tree_execute_cmd (tree, tree_map[i].command);
1094 return MSG_HANDLED;
1097 if (is_abort_char (key))
1099 if (tree->is_panel)
1101 tree->searching = 0;
1102 show_tree (tree);
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);
1116 show_tree (tree);
1117 return MSG_HANDLED;
1120 if (!command_prompt)
1122 tree_start_search (tree);
1123 tree_do_search (tree, key);
1124 return MSG_HANDLED;
1126 return tree->is_panel ? MSG_HANDLED : MSG_NOT_HANDLED;
1129 return MSG_NOT_HANDLED;
1132 /* --------------------------------------------------------------------------------------------- */
1134 static void
1135 tree_frame (Dlg_head * h, WTree * tree)
1137 tty_setcolor (NORMAL_COLOR);
1138 widget_erase ((Widget *) tree);
1139 if (tree->is_panel)
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);
1149 if (show_mini_info)
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 /* --------------------------------------------------------------------------------------------- */
1161 static cb_ret_t
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);
1168 switch (msg)
1170 case WIDGET_DRAW:
1171 tree_frame (h, tree);
1172 show_tree (tree);
1173 return MSG_HANDLED;
1175 case WIDGET_FOCUS:
1176 tree->active = 1;
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);
1184 #if 0
1185 /* FIXME: mkdir is currently defunct */
1186 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Mkdir"), tree_map, (Widget *) tree);
1187 #else
1188 buttonbar_clear_label (b, 7, (Widget *) tree);
1189 #endif
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 */
1195 show_tree (tree);
1196 return MSG_HANDLED;
1198 /* FIXME: Should find a better way of changing the color of the
1199 selected item */
1201 case WIDGET_UNFOCUS:
1202 tree->active = 0;
1203 tree->searching = 0;
1204 show_tree (tree);
1205 return MSG_HANDLED;
1207 case WIDGET_KEY:
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);
1216 return MSG_HANDLED;
1218 default:
1219 return default_proc (msg, parm);
1223 /* --------------------------------------------------------------------------------------------- */
1224 /*** public functions ****************************************************************************/
1225 /* --------------------------------------------------------------------------------------------- */
1227 WTree *
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;
1242 tree->active = 0;
1244 /* We do not want to keep the cursor */
1245 widget_want_cursor (tree->widget, 0);
1246 load_tree (tree);
1247 return tree;
1250 /* --------------------------------------------------------------------------------------------- */
1252 void
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 */
1269 char *
1270 tree_selected_name (const WTree * tree)
1272 return tree->selected_ptr->name;
1275 /* --------------------------------------------------------------------------------------------- */
1277 void
1278 sync_tree (const char *path)
1280 tree_chdir (the_tree, path);
1283 /* --------------------------------------------------------------------------------------------- */
1285 WTree *
1286 find_tree (struct Dlg_head *h)
1288 return (WTree *) find_widget_type (h, tree_callback);
1291 /* --------------------------------------------------------------------------------------------- */