/***************************************************************************/
/***************************************************************************/
/* */
/* (c) 1995-1999. The Regents of the University of California. All */
/* rights reserved. */
/* */
/* This work was produced at the University of California, Lawrence */
/* Livermore National Laboratory (UC LLNL) under contract no. */
/* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */
/* (DOE) and The Regents of the University of California (University) */
/* for the operation of UC LLNL. Copyright is reserved to the */
/* University for purposes of controlled dissemination, */
/* commercialization through formal licensing, or other disposition */
/* under terms of Contract 48; DOE policies, regulations and orders; */
/* and U.S. statutes. The rights of the Federal Government are */
/* reserved under Contract 48 subject to the restrictions agreed upon */
/* by the DOE and University. */
/* */
/* */
/* DISCLAIMER */
/* */
/* This software was prepared as an account of work sponsored by an */
/* agency of the United States Government. Neither the United States */
/* Government nor the University of California nor any of their */
/* employees, makes any warranty, express or implied, or assumes any */
/* liability or responsibility for the accuracy, completeness, or */
/* usefulness of any information, apparatus, product, or process */
/* disclosed, or represents that its specific commercial products, */
/* process, or service by trade name, trademark, manufacturer, or */
/* otherwise, does not necessarily constitute or imply its */
/* endorsement, recommendation, or favoring by the United States */
/* Government or the University of California. The views and opinions */
/* of the authors expressed herein do not necessarily state or reflect */
/* those of the United States Government or the University of */
/* California, and shall not be used for advertising or product */
/* endorsement purposes. */
/* */
/* Permission to use, copy, modify and distribute this software and its */
/* documentation for any non-commercial purpose, without fee, is */
/* hereby granted, provided that the above copyright notice and this */
/* permission notice appear in all copies of the software and */
/* supporting documentation, and that all UC LLNL identification in */
/* the user interface remain unchanged. The title to copyright LLNL */
/* XDIR shall at all times remain with The Regents of the University */
/* of California and users agree to preserve same. Users seeking the */
/* right to make derivative works with LLNL XDIR for commercial */
/* purposes may obtain a license from the Lawrence Livermore National */
/* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */
/* Livermore, CA 94550. */
/* */
/***************************************************************************/
/***************************************************************************/
#include <Xm/Xm.h>
#include <string.h>
#include "xdir.h"
#include "resources.h"
#include "list.h"
#include "history.h"
struct dirwin_st *dirwin_head = NULL;
struct dirwin_st *create_dir_window();
char *entry_to_rel_path();
char *links_to_path();
char **path_to_links();
struct entry_info *rel_path_to_entry();
void set_first_visible_entry();
extern struct st_host_info hinfo[];
extern Display *display;
extern int initial_layout;
extern AppData app_data;
extern int initial_tunneling_mode;
extern int initial_dotfiles_mode;
extern int initial_cache_mode;
/*
* display_dir - Display the directory specified by "path" for the
* host specified by "host". If the directory is already
* being displayed, pop its window to the top. If the
* directory is not already displayed and if "dirwin" is
* is non-null then display the directory in the window
* specified by "dirwin". If the directory is not already
* displayed and if "dirwin" is null, then create a new
* directory window to display the directory in. Set
* "refresh_existing" to True if you want a directory
* window that already displays "dir" to be refreshed.
* Set "raise" to True is you want a directory window
* that already displays "dir" to be raised. Note that
* "refresh_existing" and "raise" are independent. Set
* "cfetch_ok" to True if it is ok to fetch the directory
* list from the cache. Set "cstore_ok" to True if it is
* ok to use the directory list to update the cache. Returns
* 0 if successful, -3 for lost connection, -6 for stop
* button pushed, and -1 for other errors.
*/
display_dir(host, dirwin, path, refresh_existing, raise, cstore_ok, cfetch_ok)
int host;
struct dirwin_st *dirwin;
char *path;
int refresh_existing;
int raise;
int cstore_ok;
int cfetch_ok;
{
struct dirwin_st *temp_dirwin;
char *true_path;
int already_displayed = False;
struct sl_struct *dlist;
int retval;
int i;
int width;
int layout;
int tunneling_mode;
int dotfiles_mode;
int cache_mode;
struct entry_info *einfo;
int need_to_create;
char *temp;
char *username;
char *anchor_rel_path = NULL;
int indx;
int used_cache = False;
/* This could take some time */
use_busy_cursor();
/* Determine true path of directory */
retval = determine_true_path(host, path, True, cstore_ok, cfetch_ok,
&true_path);
if (retval < 0) {
restore_prev_cursor();
return retval;
}
/* Is directory already being displayed? */
if (is_dir_displayed(host, true_path, &temp_dirwin, &einfo)) {
if (einfo)
collapse_subtree(&einfo, True);
else {
dirwin = temp_dirwin;
already_displayed = True;
if (raise)
XMapRaised(display, XtWindow(dirwin->w_shell));
if (refresh_existing) {
if (dirwin->layout == TREE) {
retval = re_expand_tree(dirwin, cstore_ok, cfetch_ok);
XtFree(true_path);
restore_prev_cursor();
switch (retval) {
case 1:
report_cache_use(dirwin, True);
return 0;
case 0:
report_cache_use(dirwin, False);
default:
return retval;
}
}
} else {
XtFree(true_path);
restore_prev_cursor();
return 0;
}
}
}
/* Will a new dialog be needed to display the directory? */
if (already_displayed || (dirwin && (dirwin->host == host)
&& dirwin->tunneling_mode)) {
need_to_create = False;
layout = dirwin->layout;
dotfiles_mode = dirwin->dotfiles_mode;
if (raise)
XMapRaised(display, XtWindow(dirwin->w_shell));
} else {
need_to_create = True;
if (dirwin) {
tunneling_mode = dirwin->tunneling_mode;
layout = dirwin->layout;
dotfiles_mode = dirwin->dotfiles_mode;
cache_mode = dirwin->cache_mode;
} else {
tunneling_mode = initial_tunneling_mode;
layout = initial_layout;
dotfiles_mode = initial_dotfiles_mode;
cache_mode = initial_cache_mode;
}
}
/* Get directory list */
retval = get_dirlist(host, true_path, layout, dotfiles_mode, cstore_ok,
cfetch_ok, &dlist);
if (retval < 0) {
XtFree(true_path);
restore_prev_cursor();
return retval;
}
if (retval == 1)
used_cache = True;
/* Remember topmost visible entry */
if (already_displayed && refresh_existing && dirwin->nentries) {
indx = dirwin->first_visible_row;
if (indx)
anchor_rel_path = entry_to_rel_path(&dirwin->entries[indx]);
}
/* Create dir window and inherit modes from "parent" dir window */
if (need_to_create) {
dirwin = create_dir_window();
dirwin->host = host;
dirwin->layout = layout;
dirwin->tunneling_mode = tunneling_mode;
dirwin->dotfiles_mode = dotfiles_mode;
dirwin->cache_mode = cache_mode;
update_goto_menu(dirwin);
update_launch_menus(dirwin);
update_xfer_mode_menu(dirwin);
update_viewed_files_menu(dirwin);
if (host == LOCAL)
XtSetSensitive(dirwin->w_quotedItem, False);
}
/* Update directory name */
XtFree(dirwin->dirname);
dirwin->dirname = XtNewString(true_path);
/* Update title bar */
if (host == LOCAL)
username = XtNewString("Local");
else
username = XtNewString(hinfo[dirwin->host].username);
temp = XtMalloc(strlen(hinfo[dirwin->host].hostname)+strlen(username)
+strlen(dirwin->dirname)+8);
sprintf(temp, "%s (%s) %s", hinfo[dirwin->host].hostname, username,
dirwin->dirname);
XtFree(username);
XtVaSetValues(dirwin->w_shell, XmNtitle, temp, NULL);
XtFree(temp);
/* Update the "Go to Ancestors" menus */
update_ancestors_menus(dirwin);
/* Allocate space to hold directory entry info */
for (i=0; i<dirwin->nentries; i++) {
XtFree(dirwin->entries[i].name);
XtFree(dirwin->entries[i].info);
}
if (dirwin->nentries)
XtFree((char *)dirwin->entries);
if (dlist->nentries)
dirwin->entries = (struct entry_info *)XtMalloc(dlist->nentries*
sizeof(struct entry_info));
dirwin->nentries = dlist->nentries;
/* Save information about directory entries */
dirwin->max_entry_width = 0;
for (i=0; i<dlist->nentries; i++) {
einfo = &dirwin->entries[i];
switch (dirwin->layout) {
case TABULAR:
einfo->name = XtNewString(dlist->entries[i]);
einfo->type = UNKNOWN_TYPE;
einfo->info = NULL;
width = XTextWidth(app_data.variable_width_layout_font,
einfo->name, strlen(einfo->name))+2*TMARGIN;
einfo->width = width;
break;
case ICONIC:
case TREE:
parse_short_entry(hinfo[host].system, dlist->entries[i],
&einfo->name, &einfo->type);
einfo->info = NULL;
width = XTextWidth(app_data.variable_width_layout_font,
einfo->name, strlen(einfo->name))+2*TMARGIN+IWIDTH+IMARGIN;
einfo->width = width;
break;
case FULL_INFO:
parse_long_entry(hinfo[host].system, hinfo[host].server,
dlist->entries[i], &einfo->name, &einfo->info, &einfo->type);
width = XTextWidth(app_data.fixed_width_layout_font,
einfo->info, strlen(einfo->info))+2*TMARGIN;
einfo->width = width;
break;
}
einfo->state = UNSELECTED;
einfo->indx = i;
einfo->level = 0;
einfo->dirwin = dirwin;
einfo->expanded = False;
dirwin->max_entry_width = MAX(dirwin->max_entry_width, width);
}
dirwin->entry_height = app_data.variable_width_layout_font->ascent+
app_data.variable_width_layout_font->descent;
switch (dirwin->layout) {
case TABULAR:
case FULL_INFO:
dirwin->entry_height += 2*TMARGIN;
break;
case ICONIC:
case TREE:
dirwin->entry_height = MAX(dirwin->entry_height, IHEIGHT)+2*TMARGIN;
}
/* Update cache of referenced directories */
add_to_history(DIRECTORY, hinfo[host].hostname, true_path);
update_goto_menus_for_host(host);
/* Perform geometry calculations for directory display */
calc_dirwin_geometry(dirwin);
/* Redraw changed part of directory display */
if (need_to_create)
reset_scrollbars(dirwin, 0, 0);
else {
if (anchor_rel_path) {
set_first_visible_entry(dirwin, anchor_rel_path);
XtFree(anchor_rel_path);
} else {
reset_scrollbars(dirwin, 0, 0);
redraw_entire_dir(dirwin);
}
}
/* Free up memory */
XtFree(true_path);
release_array_list(dlist);
update_dir_controls();
update_wins_menu();
restore_prev_cursor();
report_cache_use(dirwin, used_cache);
return 0;
}
/*
* close_directory_window - Removes the specified directory window and its
* associated data structure.
*/
void
close_directory_window(dirwin)
struct dirwin_st *dirwin;
{
struct dirwin_st *dwin;
int i;
int host = dirwin->host;
/* If stop button is showing, get rid of it */
if (stop_button_is_showing(dirwin))
hide_stop_button();
/* Remove dialog from cursor linked list */
remove_dialog_from_list(dirwin->w_shell);
/* Destroy window */
XtDestroyWidget(dirwin->w_shell);
/* Release associated memory */
for (i=0; i<dirwin->nentries; i++) {
XtFree(dirwin->entries[i].name);
XtFree(dirwin->entries[i].info);
}
if (dirwin->nentries)
XtFree((char *)dirwin->entries);
XtFree(dirwin->dirname);
/* Disconnect from linked list */
if (dirwin->prev)
dirwin->prev->next = dirwin->next;
else
dirwin_head = dirwin->next;
if (dirwin->next)
dirwin->next->prev = dirwin->prev;
XtFree((char *)dirwin);
/* Clean up if this is last directory window for remote host */
dwin = dirwin_head;
while (dwin && (dwin->host != host))
dwin = dwin->next;
if ((dwin == NULL) && (host != LOCAL)) {
close(hinfo[host].ctrl_fd);
release_host(host);
}
/* Update directory window controls */
update_wins_menu();
update_dir_controls();
}
void
clear_selected_entries()
{
struct dirwin_st *dirwin;
int i;
dirwin = dirwin_head;
while(dirwin) {
if (dirwin->has_selection) {
for (i=0; i<dirwin->nentries; i++)
deselect_entry(&dirwin->entries[i]);
dirwin->has_selection = False;
return;
}
dirwin = dirwin->next;
}
}
/*
* has_selected_entries - Returns true if dirwin contains selected
* entries, else False.
*/
has_selected_entries(dirwin)
struct dirwin_st *dirwin;
{
int i;
for (i=0; i<dirwin->nentries; i++)
if (dirwin->entries[i].state == SELECTED)
return True;
return False;
}
/*
* cb_refresh_dir - Callback to refresh a directory display.
*/
void
cb_refresh_dir(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
int retval;
/* Start operation */
if (!start_op(False))
return;
/* Clear error flag */
raise_okflag();
/* Make operation interruptable for remote hosts */
if (dirwin->host != LOCAL)
show_stop_button(dirwin);
/* Make sure remote connection is good */
if (dirwin->host != LOCAL) {
retval = check_connection(dirwin->host, dirwin);
if (retval < 0) {
switch (retval) {
case -6:
record_abort("Refresh Directory Window");
break;
case -1:
record_and_alert("Unable to refresh directory.",
dirwin->w_shell);
}
hide_stop_button();
end_op();
return;
}
}
/* Can assume directory is already displayed */
retval = display_dir(dirwin->host, dirwin, dirwin->dirname, True, False,
dirwin->cache_mode, False);
switch (retval) {
case -6:
record_abort("Refresh Directory Window");
break;
case -3:
restore_lost_connection(dirwin->host, dirwin);
break;
case -1:
record_and_alert("Unable to refresh directory.", dirwin->w_shell);
}
if (dirwin->host != LOCAL)
hide_stop_button();
/* End operation */
end_op();
}
/*
* is_dir_displayed - Returns True if indicated directory is displayed,
* else False. If directory is found, "dirwin" is set
* point to the directory window structure. If the
* directory is being displayed as a lower-level
* subdirectory, "einfo", a pointer to the entry
* structure for that directory is also returned
* (otherwise einfo is set to NULL). "path" must be
* the full true path name (e.g., "/a/b/c").
*/
is_dir_displayed(host, path, dirwin, einfo)
int host;
char *path;
struct dirwin_st **dirwin;
struct entry_info **einfo;
{
struct dirwin_st *dwin;
struct entry_info *ret_einfo;
int nlinks;
char **links;
char **parent_links;
char **rel_path_links;
char **ptr;
char *parent_dir;
char *rel_path;
int system = hinfo[host].system;
int i;
int j;
/* Does directory have its own display? */
dwin = dirwin_head;
while (dwin) {
if (dwin->host == host && strcmp(dwin->dirname, path) == 0) {
*dirwin = dwin;
*einfo = NULL;
return True;
}
dwin = dwin->next;
}
/* Is an ancestor being displayed? Find the closest one. */
links = path_to_links(system, path);
nlinks = 0;
ptr = links;
while (*ptr++)
nlinks++;
for (i=nlinks-1; i>0; i--) {
parent_links = (char **)XtMalloc(sizeof(char *)*(i+1));
for (j=0; j<i; j++)
parent_links[j] = XtNewString(links[j]);
parent_links[i] = NULL;
parent_dir = links_to_path(system, parent_links, i);
release_path_links(parent_links);
dwin = dirwin_head;
while (dwin) {
if (dwin->host == host && !strcmp(dwin->dirname, parent_dir)) {
XtFree(parent_dir);
goto found_ancestor;
}
dwin = dwin->next;
}
XtFree(parent_dir);
}
release_path_links(links);
return False;
found_ancestor:
/* Is directory being displayed as subdirectory of ancestor? */
if (dwin->layout != TREE) {
release_path_links(links);
return False;
}
rel_path_links = (char **)XtMalloc(sizeof(char *)*(nlinks-i+1));
for (j=0; j<nlinks-i; j++)
rel_path_links[j] = XtNewString(links[i+j]);
rel_path_links[nlinks-i] = NULL;
rel_path = links_to_path(system, rel_path_links, nlinks-i);
release_path_links(rel_path_links);
release_path_links(links);
ret_einfo = rel_path_to_entry(dwin, rel_path);
XtFree(rel_path);
if (ret_einfo && ret_einfo->expanded) {
*dirwin = dwin;
*einfo = ret_einfo;
return True;
} else
return False;
}
/*
* rel_path_to_entry - Return a pointer to the info for the entry
* specifed by "path", a partial directory path.
* Returns NULL if entry not found.
*/
struct entry_info *
rel_path_to_entry(dirwin, path)
struct dirwin_st *dirwin;
char *path;
{
char **links;
char **link_ptr;
char *ptr;
char *entry;
int i;
int level = 0;
int system = hinfo[dirwin->host].system;
if (dirwin->nentries == 0)
return NULL;
links = path_to_links(system, path);
link_ptr = links;
if (*link_ptr == NULL)
fatal_error("Bug in rel_path_to_entry()");
for (i=0; i<dirwin->nentries; i++) {
if (dirwin->entries[i].level < level)
break;
entry = XtNewString(dirwin->entries[i].name);
if ((system == SYS_VMS) && (ptr = strstr(entry, ".dir;")))
*(ptr+4) = '\0';
if ((dirwin->entries[i].level == level) && !strcmp(entry, *link_ptr)) {
level++;
link_ptr++;
if (*link_ptr == NULL) {
XtFree(entry);
release_path_links(links);
return &dirwin->entries[i];
}
}
XtFree(entry);
}
release_path_links(links);
return NULL;
}
/*
* rel_path_to_nearest_entry - Return a pointer to the info for the entry
* specifed by "path", a partial directory path.
* If no such entry exists, return a pointer to
* the info for the entry nearest to where the
* entry for "path" would be. Returns 0 if
* there are no entries in the dirwin.
*/
struct entry_info *
rel_path_to_nearest_entry(dirwin, path)
struct dirwin_st *dirwin;
char *path;
{
char *path_copy;
char *link;
int i;
int level = 0;
int retval;
if (dirwin->nentries == 0)
return NULL;
path_copy = XtNewString(path);
if ((link = strtok(path_copy, "/")) == NULL)
fatal_error("Bug in rel_path_to_entry()");
for (i=0; i<dirwin->nentries; i++) {
if (dirwin->entries[i].level < level)
break;
if (dirwin->entries[i].level == level) {
retval = strcmp(dirwin->entries[i].name, link);
if (retval == 0) {
level++;
if ((link = strtok(NULL, "/")) == NULL)
break;
} else if (retval > 0)
break;
}
}
XtFree(path_copy);
i = MIN(i, dirwin->nentries-1);
return &dirwin->entries[i];
}
/*
* set_first_visible_entry - In the specified directory window, position the
* entry whose relative path is closest to the one
* given on the first visible row.
*/
void
set_first_visible_entry(dirwin, rel_path)
struct dirwin_st *dirwin;
char *rel_path;
{
struct entry_info *einfo;
int row;
int first_visible_row;
/* Determine first visible row */
if ((einfo = rel_path_to_nearest_entry(dirwin, rel_path))) {
row = einfo->indx%dirwin->nrows;
first_visible_row =
MIN(row, MAX(0, dirwin->nentries-dirwin->nrows_visible));
} else
first_visible_row = 0;
/* Fix up scrollbars */
reset_scrollbars(dirwin, -1, first_visible_row);
/* Redraw visible part of directory display */
redraw_entire_dir(dirwin);
}
syntax highlighted by Code2HTML, v. 0.9.1