mc/src/tree.c

1079 lines
25 KiB
C
Raw Normal View History

1998-02-27 07:54:42 +03:00
/* Directory tree browser for the Midnight Commander
Copyright (C) 1994, 1995, 1996, 1997 The Free Software Foundation
Written: 1994, 1996 Janne Kukonlehto
1997 Norbert Warmuth
1996, 1999 Miguel de Icaza
1998-02-27 07:54:42 +03:00
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
1998-02-27 07:54:42 +03:00
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1998-02-27 07:54:42 +03:00
This module has been converted to be a widget.
The program load and saves the tree each time the tree widget is
created and destroyed. This is required for the future vfs layer,
it will be possible to have tree views over virtual file systems.
*/
#include <config.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
1998-02-27 07:54:42 +03:00
#include "global.h"
#include "tty.h"
1998-02-27 07:54:42 +03:00
#include "color.h"
#include "dialog.h"
#include "dir.h"
#include "dlg.h"
#include "widget.h"
#include "panel.h"
#include "mouse.h"
#include "main.h"
#include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
#include "fileopctx.h"
1998-02-27 07:54:42 +03:00
#include "help.h"
#include "key.h" /* For mi_getch() */
#include "tree.h"
#include "cmd.h"
#include "../vfs/vfs.h"
extern int command_prompt;
#define TREE_NORMALC HOT_FOCUSC
/* Specifies the display mode: 1d or 2d */
int tree_navigation_flag;
1998-02-27 07:54:42 +03:00
/* Forwards */
static void save_tree (WTree *tree);
static void tree_rescan_cmd (WTree *tree);
1998-02-27 07:54:42 +03:00
static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
#define tcallback (callback_fn) tree_callback
/* "$Id$" */
static tree_entry *back_ptr (tree_entry *ptr, int *count)
{
int i = 0;
while (ptr && ptr->prev && i < *count){
ptr = ptr->prev;
i ++;
}
*count = i;
return ptr;
}
static tree_entry *forw_ptr (tree_entry *ptr, int *count)
{
int i = 0;
while (ptr && ptr->next && i < *count){
ptr = ptr->next;
i ++;
}
*count = i;
return ptr;
}
#if 0
1998-02-27 07:54:42 +03:00
/* Add a directory to the list of directories */
static tree_entry *tree_add_entry (WTree *tree, char *name)
1998-02-27 07:54:42 +03:00
{
if (!tree)
return 0;
return tree_store_add_entry (name);
1998-02-27 07:54:42 +03:00
}
/* Append a directory to the list of directories */
static tree_entry *tree_append_entry (WTree *tree, char *name)
{
tree_entry *current, *new;
int i, len;
int submask = 0;
/* We assume the directory is not yet in the list */
new = g_new (tree_entry, 1);
if (!tree->store->tree_first){
1998-02-27 07:54:42 +03:00
/* Empty list */
tree->store->tree_first = new;
1998-02-27 07:54:42 +03:00
new->prev = NULL;
} else {
tree->tree_last->next = new;
new->prev = tree->tree_last;
}
new->next = NULL;
tree->store->tree_last = new;
1998-02-27 07:54:42 +03:00
/* Calculate attributes */
new->name = g_strdup (name);
1998-02-27 07:54:42 +03:00
len = strlen (new->name);
new->sublevel = 0;
for (i = 0; i < len; i++)
if (new->name [i] == PATH_SEP){
new->sublevel++;
new->subname = new->name + i + 1;
}
submask = 1 << new->sublevel;
submask &= (2 << new->sublevel) - 1;
new->submask = submask;
new->mark = 0;
/* Correct the submasks of the previous entries */
current = new->prev;
while (current && current->sublevel > new->sublevel){
current->submask |= 1 << new->sublevel;
current = current->prev;
}
/* The entry has now been appended */
return new;
}
#endif
static void
remove_callback (tree_entry *entry, void *data)
1998-02-27 07:54:42 +03:00
{
WTree *tree = data;
1998-02-27 07:54:42 +03:00
if (tree->selected_ptr == entry){
if (tree->selected_ptr->next)
tree->selected_ptr = tree->selected_ptr->next;
else
tree->selected_ptr = tree->selected_ptr->prev;
}
1998-02-27 07:54:42 +03:00
}
static void tree_remove_entry (WTree *tree, char *name)
1998-02-27 07:54:42 +03:00
{
tree_store_remove_entry (name);
1998-02-27 07:54:42 +03:00
}
static void tree_destroy (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_store_remove_entry_remove_hook (remove_callback);
1998-02-27 07:54:42 +03:00
save_tree (tree);
1998-02-27 07:54:42 +03:00
if (tree->tree_shown){
g_free (tree->tree_shown);
1998-02-27 07:54:42 +03:00
tree->tree_shown = 0;
}
tree->selected_ptr = NULL;
1998-02-27 07:54:42 +03:00
}
/* Loads the .mc.tree file */
static void load_tree (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_store_load ();
tree->selected_ptr = tree->store->tree_first;
tree_chdir (tree, home_dir);
1998-02-27 07:54:42 +03:00
}
/* Save the .mc.tree file */
static void save_tree (WTree *tree)
1998-02-27 07:54:42 +03:00
{
int error;
error = tree_store_save ();
if (error){
fprintf (stderr, _("Cannot open the %s file for writing:\n%s\n"), MC_TREE,
unix_error_string (error));
1998-02-27 07:54:42 +03:00
return;
}
}
static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
{
Dlg_head *h = tree->widget.parent;
int line;
/* Show mini info */
if (tree->is_panel){
if (!show_mini_info)
return;
line = tree_lines+2;
} else
line = tree_lines+1;
1998-02-27 07:54:42 +03:00
widget_move (&tree->widget, line, 1);
hline (' ', tree_cols);
widget_move (&tree->widget, line, 1);
1998-02-27 07:54:42 +03:00
if (tree->searching){
/* Show search string */
attrset (TREE_NORMALC);
attrset (FOCUSC);
addch (PATH_SEP);
1998-02-27 07:54:42 +03:00
addstr (name_trunc (tree->search_buffer, tree_cols-2));
addch (' ');
attrset (FOCUSC);
} else {
/* Show full name of selected directory */
addstr (name_trunc (tree->selected_ptr->name, tree_cols));
}
}
static void show_tree (WTree *tree)
1998-02-27 07:54:42 +03:00
{
Dlg_head *h = tree->widget.parent;
tree_entry *current;
int i, j, topsublevel;
int x, y;
int tree_lines, tree_cols;
/* Initialize */
x = y = 0;
tree_lines = tlines (tree);
tree_cols = tree->widget.cols;
attrset (TREE_NORMALC);
widget_move ((Widget*)tree, y, x);
if (tree->is_panel){
tree_cols -= 2;
x = y = 1;
}
if (tree->tree_shown)
g_free (tree->tree_shown);
tree->tree_shown = g_new (tree_entry*, tree_lines);
1998-02-27 07:54:42 +03:00
for (i = 0; i < tree_lines; i++)
tree->tree_shown [i] = NULL;
if (tree->store->tree_first)
topsublevel = tree->store->tree_first->sublevel;
1998-02-27 07:54:42 +03:00
else
topsublevel = 0;
if (!tree->selected_ptr){
tree->selected_ptr = tree->store->tree_first;
1998-02-27 07:54:42 +03:00
tree->topdiff = 0;
}
current = tree->selected_ptr;
1998-02-27 07:54:42 +03:00
/* Calculate the directory which is to be shown on the topmost line */
if (tree_navigation_flag){
i = 0;
while (current->prev && i < tree->topdiff){
current = current->prev;
if (current->sublevel < tree->selected_ptr->sublevel){
if (strncmp (current->name, tree->selected_ptr->name,
strlen (current->name)) == 0)
i++;
} else if (current->sublevel == tree->selected_ptr->sublevel){
for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
i++;
} else if (current->sublevel == tree->selected_ptr->sublevel + 1
&& strlen (tree->selected_ptr->name) > 1){
if (strncmp (current->name, tree->selected_ptr->name,
strlen (tree->selected_ptr->name)) == 0)
i++;
}
}
tree->topdiff = i;
} else
current = back_ptr (current, &tree->topdiff);
/* Loop for every line */
for (i = 0; i < tree_lines; i++){
/* Move to the beginning of the line */
widget_move (&tree->widget, y+i, x);
hline (' ', tree_cols);
widget_move (&tree->widget, y+i, x);
if (!current)
continue;
1998-02-27 07:54:42 +03:00
tree->tree_shown [i] = current;
if (current->sublevel == topsublevel){
/* Top level directory */
1998-09-22 20:13:54 +04:00
if (tree->active && current == tree->selected_ptr) {
1998-02-27 07:54:42 +03:00
if (!use_colors && !tree->is_panel)
attrset (MARKED_COLOR);
else
attrset (SELECTED_COLOR);
1998-09-22 20:13:54 +04:00
}
1998-02-27 07:54:42 +03:00
/* Show full name */
addstr (name_trunc (current->name, tree_cols - 6));
} else{
/* Sub level directory */
acs ();
/* Output branch parts */
for (j = 0; j < current->sublevel - topsublevel - 1; j++){
if (tree_cols - 8 - 3 * j < 9)
break;
addch (' ');
if (current->submask & (1 << (j + topsublevel + 1)))
addch (ACS_VLINE);
else
addch (' ');
addch (' ');
}
addch (' '); j++;
if (!current->next || !(current->next->submask & (1 << current->sublevel)))
addch (ACS_LLCORNER);
else
addch (ACS_LTEE);
addch (ACS_HLINE);
noacs ();
1998-09-22 20:13:54 +04:00
if (tree->active && current == tree->selected_ptr) {
1998-02-27 07:54:42 +03:00
/* Selected directory -> change color */
if (!use_colors && !tree->is_panel)
attrset (MARKED_COLOR);
else
attrset (SELECTED_COLOR);
1998-09-22 20:13:54 +04:00
}
1998-02-27 07:54:42 +03:00
/* Show sub-name */
addch (' ');
addstr (name_trunc (current->subname,
tree_cols - 2 - 4 - 3 * j));
}
addch (' ');
1998-02-27 07:54:42 +03:00
/* Return to normal color */
attrset (TREE_NORMALC);
/* Calculate the next value for current */
current = current->next;
1998-02-27 07:54:42 +03:00
if (tree_navigation_flag){
while (current){
if (current->sublevel < tree->selected_ptr->sublevel){
if (strncmp (current->name, tree->selected_ptr->name,
strlen (current->name)) == 0)
break;
} else if (current->sublevel == tree->selected_ptr->sublevel){
for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
break;
} else if (current->sublevel == tree->selected_ptr->sublevel+1
&& strlen (tree->selected_ptr->name) > 1){
if (strncmp (current->name, tree->selected_ptr->name,
strlen (tree->selected_ptr->name)) == 0)
break;
}
current = current->next;
}
}
1998-02-27 07:54:42 +03:00
}
tree_show_mini_info (tree, tree_lines, tree_cols);
}
static void check_focus (WTree *tree)
{
if (tree->topdiff < 3)
tree->topdiff = 3;
else if (tree->topdiff >= tlines (tree) - 3)
tree->topdiff = tlines (tree) - 3 - 1;
}
static void tree_move_backward (WTree *tree, int i)
1998-02-27 07:54:42 +03:00
{
tree_entry *current;
int j = 0;
1998-02-27 07:54:42 +03:00
if (tree_navigation_flag){
current = tree->selected_ptr;
while (j < i && current->prev
&& current->prev->sublevel >= tree->selected_ptr->sublevel){
current = current->prev;
if (current->sublevel == tree->selected_ptr->sublevel){
tree->selected_ptr = current;
j ++;
}
}
i = j;
} else
tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
tree->topdiff -= i;
check_focus (tree);
}
static void tree_move_forward (WTree *tree, int i)
1998-02-27 07:54:42 +03:00
{
tree_entry *current;
int j = 0;
if (tree_navigation_flag){
current = tree->selected_ptr;
while (j < i && current->next
&& current->next->sublevel >= tree->selected_ptr->sublevel){
current = current->next;
if (current->sublevel == tree->selected_ptr->sublevel){
tree->selected_ptr = current;
j ++;
}
}
i = j;
} else
tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
tree->topdiff += i;
check_focus (tree);
}
static void tree_move_to_child (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_entry *current;
/* Do we have a starting point? */
if (!tree->selected_ptr)
return;
/* Take the next entry */
current = tree->selected_ptr->next;
/* Is it the child of the selected entry */
if (current && current->sublevel > tree->selected_ptr->sublevel){
/* Yes -> select this entry */
tree->selected_ptr = current;
tree->topdiff++;
check_focus (tree);
} else {
/* No -> rescan and try again */
tree_rescan_cmd (tree);
current = tree->selected_ptr->next;
if (current && current->sublevel > tree->selected_ptr->sublevel){
tree->selected_ptr = current;
tree->topdiff++;
check_focus (tree);
}
}
}
static int tree_move_to_parent (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_entry *current;
tree_entry *old;
1998-02-27 07:54:42 +03:00
if (!tree->selected_ptr)
return 0;
old = tree->selected_ptr;
current = tree->selected_ptr->prev;
while (current && current->sublevel >= tree->selected_ptr->sublevel){
current = current->prev;
tree->topdiff--;
}
if (!current)
current = tree->store->tree_first;
1998-02-27 07:54:42 +03:00
tree->selected_ptr = current;
check_focus (tree);
return tree->selected_ptr != old;
}
static void tree_move_to_top (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree->selected_ptr = tree->store->tree_first;
1998-02-27 07:54:42 +03:00
tree->topdiff = 0;
}
static void tree_move_to_bottom (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree->selected_ptr = tree->store->tree_last;
1998-02-27 07:54:42 +03:00
tree->topdiff = tlines (tree) - 3 - 1;
}
void tree_chdir (WTree *tree, char *dir)
{
tree_entry *current;
current = tree_store_whereis (dir);
1998-02-27 07:54:42 +03:00
if (current){
tree->selected_ptr = current;
check_focus (tree);
}
}
1998-12-03 00:27:27 +03:00
void
sync_tree (char *path)
{
tree_chdir (the_tree, path);
}
1998-02-27 07:54:42 +03:00
/* Handle mouse click */
static void tree_event (WTree *tree, int y)
1998-02-27 07:54:42 +03:00
{
if (tree->tree_shown [y]){
tree->selected_ptr = tree->tree_shown [y];
tree->topdiff = y;
}
show_tree (tree);
}
static void chdir_sel (WTree *tree);
static void maybe_chdir (WTree *tree)
{
if (!(xtree_mode && tree->is_panel))
return;
if (is_idle ())
chdir_sel (tree);
}
/* Mouse callback */
static int event_callback (Gpm_Event *event, WTree *tree)
{
if (!(event->type & GPM_UP))
return MOU_ENDLOOP;
if (tree->is_panel)
event->y--;
1998-02-27 07:54:42 +03:00
event->y--;
if (!tree->active)
change_panel ();
if (event->y < 0){
tree_move_backward (tree, tlines (tree) - 1);
show_tree (tree);
}
else if (event->y >= tlines (tree)){
tree_move_forward (tree, tlines (tree) - 1);
show_tree (tree);
} else {
tree_event (tree, event->y);
if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
chdir_sel (tree);
}
}
return MOU_ENDLOOP;
}
/* Search tree for text */
static int search_tree (WTree *tree, char *text)
1998-02-27 07:54:42 +03:00
{
tree_entry *current;
int len;
int wrapped = 0;
int found = 0;
len = strlen (text);
current = tree->selected_ptr;
found = 0;
while (!wrapped || current != tree->selected_ptr){
if (strncmp (current->subname, text, len) == 0){
tree->selected_ptr = current;
found = 1;
break;
}
current = current->next;
if (!current){
current = tree->store->tree_first;
1998-02-27 07:54:42 +03:00
wrapped = 1;
}
tree->topdiff++;
}
check_focus (tree);
return found;
}
static void tree_do_search (WTree *tree, int key)
{
int l;
l = strlen (tree->search_buffer);
if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
tree->search_buffer [--l] = 0;
else {
if (key && l < sizeof (tree->search_buffer)){
tree->search_buffer [l] = key;
tree->search_buffer [l+1] = 0;
l++;
}
}
if (!search_tree (tree, tree->search_buffer))
tree->search_buffer [--l] = 0;
1998-02-27 07:54:42 +03:00
show_tree (tree);
maybe_chdir (tree);
}
static void tree_rescan_cmd (WTree *tree)
1998-02-27 07:54:42 +03:00
{
char old_dir [MC_MAXPATHLEN];
if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
mc_chdir (tree->selected_ptr->name))
return;
tree_store_rescan (tree->selected_ptr->name);
1998-02-27 07:54:42 +03:00
mc_chdir (old_dir);
}
static int tree_forget_cmd (WTree *tree)
1998-02-27 07:54:42 +03:00
{
if (tree->selected_ptr)
tree_remove_entry (tree, tree->selected_ptr->name);
return 1;
}
static void tree_copy (WTree *tree, char *default_dest)
1998-02-27 07:54:42 +03:00
{
char *dest;
off_t count = 0;
double bytes = 0;
FileOpContext *ctx;
1998-02-27 07:54:42 +03:00
if (!tree->selected_ptr)
return;
g_snprintf (cmd_buf, sizeof(cmd_buf), _("Copy \"%s\" directory to:"),
1998-02-27 07:54:42 +03:00
name_trunc (tree->selected_ptr->name, 50));
dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
if (!dest)
return;
if (!*dest){
g_free (dest);
1998-02-27 07:54:42 +03:00
return;
}
ctx = file_op_context_new ();
file_op_context_create_ui (ctx, OP_COPY, FALSE);
copy_dir_dir (ctx, tree->selected_ptr->name, dest, 1, 0, 0, 0, &count, &bytes);
file_op_context_destroy (ctx);
g_free (dest);
1998-02-27 07:54:42 +03:00
}
static void tree_help_cmd (void)
{
interactive_display (NULL, "[Directory Tree]");
1998-02-27 07:54:42 +03:00
}
static int tree_copy_cmd (WTree *tree)
{
tree_copy (tree, "");
return 1;
}
static void tree_move (WTree *tree, char *default_dest)
1998-02-27 07:54:42 +03:00
{
char *dest;
1998-02-27 07:54:42 +03:00
struct stat buf;
double bytes = 0;
off_t count = 0;
FileOpContext *ctx;
1998-02-27 07:54:42 +03:00
if (!tree->selected_ptr)
return;
g_snprintf (cmd_buf, sizeof (cmd_buf), _("Move \"%s\" directory to:"),
1998-02-27 07:54:42 +03:00
name_trunc (tree->selected_ptr->name, 50));
dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
if (!dest)
return;
if (!*dest){
g_free (dest);
1998-02-27 07:54:42 +03:00
return;
}
if (stat (dest, &buf)){
message (1, MSG_ERROR, _(" Cannot stat the destination \n %s "),
1998-02-27 07:54:42 +03:00
unix_error_string (errno));
g_free (dest);
1998-02-27 07:54:42 +03:00
return;
}
if (!S_ISDIR (buf.st_mode)){
message (1, MSG_ERROR, _(" The destination isn't a directory "));
g_free (dest);
1998-02-27 07:54:42 +03:00
return;
}
ctx = file_op_context_new ();
file_op_context_create_ui (ctx, OP_MOVE, FALSE);
move_dir_dir (ctx, tree->selected_ptr->name, dest, &count, &bytes);
file_op_context_destroy (ctx);
g_free (dest);
1998-02-27 07:54:42 +03:00
}
1998-12-03 00:27:27 +03:00
static int
tree_move_cmd (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move (tree, "");
return 1;
}
#if 0
1998-12-03 00:27:27 +03:00
static int
tree_mkdir_cmd (WTree *tree)
1998-02-27 07:54:42 +03:00
{
char old_dir [MC_MAXPATHLEN];
if (!tree->selected_ptr)
return 0;
if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
return 0;
if (chdir (tree->selected_ptr->name))
return 0;
/* FIXME
mkdir_cmd (tree);
*/
tree_rescan_cmd (tree);
chdir (old_dir);
return 1;
}
#endif
1998-02-27 07:54:42 +03:00
1998-12-03 00:27:27 +03:00
static void
tree_rmdir_cmd (WTree *tree)
1998-02-27 07:54:42 +03:00
{
char old_dir [MC_MAXPATHLEN];
off_t count = 0;
1998-12-30 22:19:24 +03:00
double bytes = 0;
FileOpContext *ctx;
1998-02-27 07:54:42 +03:00
if (tree->selected_ptr){
if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
return;
1998-02-27 07:54:42 +03:00
if (mc_chdir (PATH_SEP_STR))
return;
1998-02-27 07:54:42 +03:00
if (confirm_delete){
char *buf;
1998-02-27 07:54:42 +03:00
int result;
buf = g_strdup_printf (_(" Delete %s? "), tree->selected_ptr->name);
result = query_dialog (_(" Delete "), buf, 3, 2, _("&Yes"), _("&No"));
g_free (buf);
1998-02-27 07:54:42 +03:00
if (result != 0){
return;
1998-02-27 07:54:42 +03:00
}
}
ctx = file_op_context_new ();
file_op_context_create_ui (ctx, OP_DELETE, FALSE);
if (erase_dir (ctx, tree->selected_ptr->name, &count, &bytes) == FILE_CONT)
1998-02-27 07:54:42 +03:00
tree_forget_cmd (tree);
file_op_context_destroy (ctx);
1998-02-27 07:54:42 +03:00
mc_chdir (old_dir);
return;
1998-02-27 07:54:42 +03:00
} else
return;
1998-02-27 07:54:42 +03:00
}
static void set_navig_label (WTree *tree);
1998-12-03 00:27:27 +03:00
static void
tree_toggle_navig (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_navigation_flag = 1 - tree_navigation_flag;
set_navig_label (tree);
1998-02-27 07:54:42 +03:00
}
static void
set_navig_label (WTree *tree)
1998-02-27 07:54:42 +03:00
{
define_label_data (tree->widget.parent, (Widget *) tree,
4, tree_navigation_flag ? _("Static") : _("Dynamc"),
(buttonbarfn) tree_toggle_navig, tree);
1998-02-27 07:54:42 +03:00
}
1998-12-03 00:27:27 +03:00
static void
move_down (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move_forward (tree, 1);
show_tree (tree);
maybe_chdir (tree);
}
1998-12-03 00:27:27 +03:00
static void
move_up (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move_backward (tree, 1);
show_tree (tree);
maybe_chdir (tree);
}
1998-12-03 00:27:27 +03:00
static void
move_home (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move_to_top (tree);
show_tree (tree);
maybe_chdir (tree);
}
1998-12-03 00:27:27 +03:00
static void
move_end (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move_to_bottom (tree);
show_tree (tree);
maybe_chdir (tree);
}
1998-12-03 00:27:27 +03:00
static int
move_left (WTree *tree)
1998-02-27 07:54:42 +03:00
{
int v;
1998-02-27 07:54:42 +03:00
if (tree_navigation_flag){
v = tree_move_to_parent (tree);
show_tree (tree);
maybe_chdir (tree);
return v;
}
return 0;
}
1998-12-03 00:27:27 +03:00
static int
move_right (WTree *tree)
1998-02-27 07:54:42 +03:00
{
if (tree_navigation_flag){
tree_move_to_child (tree);
show_tree (tree);
maybe_chdir (tree);
return 1;
}
return 0;
}
1998-12-03 00:27:27 +03:00
static void
move_prevp (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move_backward (tree, tlines (tree) - 1);
show_tree (tree);
maybe_chdir (tree);
}
1998-12-03 00:27:27 +03:00
static void
move_nextp (WTree *tree)
1998-02-27 07:54:42 +03:00
{
tree_move_forward (tree, tlines (tree) - 1);
show_tree (tree);
maybe_chdir (tree);
}
1998-12-03 00:27:27 +03:00
static void
chdir_sel (WTree *tree)
1998-02-27 07:54:42 +03:00
{
if (!tree->is_panel){
tree->done = 1;
return;
}
change_panel ();
if (do_cd (tree->selected_ptr->name, cd_exact)){
paint_panel (cpanel);
select_item (cpanel);
} else {
message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
1998-02-27 07:54:42 +03:00
tree->selected_ptr->name, unix_error_string (errno));
}
change_panel ();
show_tree (tree);
return;
}
1998-12-03 00:27:27 +03:00
static void
tree_start_search (WTree *tree)
1998-02-27 07:54:42 +03:00
{
int i;
if (tree->searching){
if (tree->selected_ptr == tree->store->tree_last)
1998-02-27 07:54:42 +03:00
tree_move_to_top(tree);
else {
/* set navigation mode temporarily to 'Static' because in
1998-02-27 07:54:42 +03:00
* dynamic navigation mode tree_move_forward will not move
* to a lower sublevel if necessary (sequent searches must
* start with the directory followed the last found directory)
*/
1998-02-27 07:54:42 +03:00
i = tree_navigation_flag;
tree_navigation_flag = 0;
tree_move_forward (tree, 1);
tree_navigation_flag = i;
}
tree_do_search (tree, 0);
}
else {
tree->searching = 1;
tree->search_buffer[0] = 0;
}
}
static const key_map tree_keymap [] = {
1998-02-27 07:54:42 +03:00
{ XCTRL('n'), move_down },
{ XCTRL('p'), move_up },
{ KEY_DOWN, move_down },
{ KEY_UP, move_up },
{ '\n', chdir_sel },
{ KEY_ENTER, chdir_sel },
{ KEY_HOME, move_home },
{ KEY_C1, move_end },
{ KEY_END, move_end },
{ KEY_A1, move_home },
{ KEY_NPAGE, move_nextp },
{ KEY_PPAGE, move_prevp },
{ XCTRL('v'), move_nextp },
{ ALT('v'), move_prevp },
{ XCTRL('p'), move_up },
{ XCTRL('p'), move_down },
{ XCTRL('s'), tree_start_search },
{ ALT('s'), tree_start_search },
1998-02-27 07:54:42 +03:00
{ XCTRL('r'), tree_rescan_cmd },
{ KEY_DC, tree_rmdir_cmd },
1998-02-27 07:54:42 +03:00
{ 0, 0 }
};
1998-12-03 00:27:27 +03:00
static inline int
tree_key (WTree *tree, int key)
1998-02-27 07:54:42 +03:00
{
int i;
for (i = 0; tree_keymap [i].key_code; i++){
if (key == tree_keymap [i].key_code){
if (tree_keymap [i].fn != tree_start_search)
1998-02-27 07:54:42 +03:00
tree->searching = 0;
(*tree_keymap [i].fn)(tree);
show_tree (tree);
return 1;
1998-02-27 07:54:42 +03:00
}
}
1998-02-27 07:54:42 +03:00
/* We do not want to use them if we do not need to */
/* Input line may want to take the motion key event */
if (key == KEY_LEFT)
return move_left (tree);
if (key == KEY_RIGHT)
return move_right (tree);
1998-02-27 07:54:42 +03:00
if (is_abort_char (key)) {
if (tree->is_panel) {
tree->searching = 0;
show_tree (tree);
return 1; /* eat abort char */
}
return 0; /* modal tree dialog: let upper layer see the
abort character and close the dialog */
1998-02-27 07:54:42 +03:00
}
/* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
if (tree->searching){
tree_do_search (tree, key);
show_tree (tree);
return 1;
}
1998-02-27 07:54:42 +03:00
if (!command_prompt) {
tree_start_search (tree);
tree_do_search (tree, key);
return 1;
}
return tree->is_panel;
1998-02-27 07:54:42 +03:00
}
return 0;
1998-02-27 07:54:42 +03:00
}
1998-12-03 00:27:27 +03:00
static void
tree_frame (Dlg_head *h, WTree *tree)
1998-02-27 07:54:42 +03:00
{
attrset (NORMAL_COLOR);
widget_erase ((Widget*) tree);
if (tree->is_panel)
draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
tree->widget.cols);
1998-02-27 07:54:42 +03:00
if (show_mini_info && tree->is_panel){
widget_move (tree, tlines (tree) + 1, 1);
hline (ACS_HLINE, tree->widget.cols - 2);
}
}
1998-12-03 00:27:27 +03:00
static int
tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
1998-02-27 07:54:42 +03:00
{
switch (msg){
case WIDGET_DRAW:
tree_frame (h, tree);
show_tree (tree);
return 1;
case WIDGET_KEY:
return tree_key (tree, par);
case WIDGET_FOCUS:
tree->active = 1;
define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
define_label_data (h, (Widget *)tree,
2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
define_label_data (h, (Widget *)tree,
3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
define_label_data (h, (Widget *)tree,
5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
define_label_data (h, (Widget *)tree,
6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
1998-02-27 07:54:42 +03:00
#if 0
/* FIXME: mkdir is currently defunct */
define_label_data (h, (Widget *)tree,
7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
1998-02-27 07:54:42 +03:00
#else
define_label (h, (Widget *)tree, 7, "", 0);
#endif
define_label_data (h, (Widget *)tree,
8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
set_navig_label (tree);
1998-02-27 07:54:42 +03:00
redraw_labels (h, (Widget *)tree);
1998-02-27 07:54:42 +03:00
/* FIXME: Should find a better way of only displaying the
currently selected item */
1998-02-27 07:54:42 +03:00
show_tree (tree);
return 1;
/* FIXME: Should find a better way of changing the color of the
selected item */
case WIDGET_UNFOCUS:
tree->active = 0;
show_tree (tree);
return 1;
}
return default_proc (h, msg, par);
}
1998-12-03 00:27:27 +03:00
WTree *
tree_new (int is_panel, int y, int x, int lines, int cols)
1998-02-27 07:54:42 +03:00
{
WTree *tree = g_new (WTree, 1);
1998-02-27 07:54:42 +03:00
init_widget (&tree->widget, y, x, lines, cols, tcallback,
(destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
tree->is_panel = is_panel;
tree->selected_ptr = 0;
tree->store = tree_store_get ();
tree_store_add_entry_remove_hook (remove_callback, tree);
1998-02-27 07:54:42 +03:00
tree->tree_shown = 0;
tree->search_buffer [0] = 0;
tree->topdiff = tree->widget.lines / 2;
tree->searching = 0;
tree->done = 0;
tree->active = 0;
1998-02-27 07:54:42 +03:00
/* We do not want to keep the cursor */
widget_want_cursor (tree->widget, 0);
load_tree (tree);
return tree;
}