/***************************************************************************/
/***************************************************************************/
/* */
/* (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 "xdir.h"
#include "resources.h"
#include "list.h"
struct ref_st {
char *name;
struct ref_st *subtree;
};
extern AppData app_data;
extern struct st_host_info hinfo[];
char *entry_to_rel_path();
char *entry_to_full_path();
/*
* expand_subtree - Expand subtree at directory entry specified by
* "expand_einfo". 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, 1 if cache was used, -3 for lost
* connection, -6 for stop button pressed, and -1
* for other errors.
*/
expand_subtree(expand_einfo, cstore_ok, cfetch_ok)
struct entry_info **expand_einfo;
int cstore_ok;
int cfetch_ok;
{
struct dirwin_st *dirwin = (*expand_einfo)->dirwin;
int expand_index;
int retval;
int used_cache = False;
/* This could take some time */
use_busy_cursor();
/* Expand the directory */
expand_index = (*expand_einfo)->indx;
retval = re_expand_subtree(expand_einfo, NULL, cstore_ok, cfetch_ok);
if (retval < 0) {
update_dir_controls();
restore_prev_cursor();
return retval;
}
if (retval == 1)
used_cache = True;
/* Perform geometry calculations for directory display */
calc_dirwin_geometry(dirwin);
/* Fix up scrollbars */
reset_scrollbars(dirwin, -1, -1);
/* Redraw changed part of directory display */
redraw_dir_rows(dirwin, expand_index);
update_dir_controls();
restore_prev_cursor();
if (used_cache)
return 1;
else
return 0;
}
/*
* collapse_subtree - Collapse subtree at directory entry specified by
* "collapse_einfo". Update display if "update_display"
* is set.
*/
void
collapse_subtree(collapse_einfo, update_display)
struct entry_info **collapse_einfo;
int update_display;
{
struct dirwin_st *dirwin = (*collapse_einfo)->dirwin;
int x;
int width;
Dimension drawing_area_width;
Dimension drawing_area_height;
int count = 0;
int start_index;
struct entry_info *new_entries;
int i;
int collapse_index = (*collapse_einfo)->indx;
int old_first_visible_row;
/* Get rid of collapsed directory's entries */
start_index = collapse_index+1;
for (i=start_index; i<dirwin->nentries; i++)
if (dirwin->entries[i].level > (*collapse_einfo)->level)
count++;
else
break;
new_entries = (struct entry_info *)XtMalloc(
(dirwin->nentries-count)*sizeof(struct entry_info));
bcopy(dirwin->entries, new_entries,
start_index*sizeof(struct entry_info));
bcopy(&dirwin->entries[start_index+count], &new_entries[start_index],
(dirwin->nentries-count-start_index)*sizeof(struct entry_info));
for (i=start_index; i<start_index+count; i++) {
XtFree(dirwin->entries[i].name);
XtFree(dirwin->entries[i].info);
}
XtFree((char *)dirwin->entries);
dirwin->entries = new_entries;
dirwin->nentries -= count;
for (i=start_index; i<dirwin->nentries; i++)
dirwin->entries[i].indx = i;
dirwin->entries[collapse_index].expanded = False;
/* Adjust entry pointer */
*collapse_einfo = &dirwin->entries[collapse_index];
/* Determine new maximum entry width */
dirwin->max_entry_width = 0;
for (i=0; i<dirwin->nentries; i++) {
width = XTextWidth(app_data.variable_width_layout_font,
dirwin->entries[i].name,
strlen(dirwin->entries[i].name))+2*TMARGIN+IWIDTH+IMARGIN;
dirwin->max_entry_width = MAX(dirwin->max_entry_width, width);
}
if (update_display == False)
return;
/* Perform geometry calculations for directory display */
calc_dirwin_geometry(dirwin);
old_first_visible_row = dirwin->first_visible_row;
reset_scrollbars(dirwin, -1, -1);
/* Redraw changed part of directory display */
XtVaGetValues(dirwin->w_drawingArea,
XmNwidth, &drawing_area_width,
XmNheight, &drawing_area_height,
NULL
);
x = virtual_x(dirwin, 0);
width = drawing_area_width;
if (dirwin->first_visible_row != old_first_visible_row)
redraw_entire_dir(dirwin);
else
redraw_dir_rows(dirwin, collapse_index);
update_dir_controls();
}
/*
* create_reference_subtree - Create a tree containing the names of the
* subdirectories of the specified directory
* entry that are expanded. Caller must call
* release_reference_subtree() to destroy
* the returned tree.
*/
struct ref_st *
create_reference_subtree(einfo)
struct entry_info *einfo;
{
struct dirwin_st *dirwin = einfo->dirwin;
struct ref_st *subtree;
int count;
int i;
/* Count number of expanded entries in directory */
count = 0;
for (i=einfo->indx+1; i<dirwin->nentries; i++) {
if (dirwin->entries[i].level <= einfo->level)
break;
if (dirwin->entries[i].level == einfo->level+1
&& dirwin->entries[i].expanded)
count++;
}
/* Allocate memory for the tree of expanded subdirectories */
subtree = (struct ref_st *)XtMalloc((count+1)*sizeof(struct ref_st));
/* Record names of expanded entries */
count = 0;
for (i=einfo->indx+1; i<dirwin->nentries; i++) {
if (dirwin->entries[i].level <= einfo->level)
break;
if (dirwin->entries[i].level == einfo->level+1
&& dirwin->entries[i].expanded) {
subtree[count].name = XtNewString(dirwin->entries[i].name);
subtree[count].subtree =
create_reference_subtree(&dirwin->entries[i]);
count++;
}
}
subtree[count].name = NULL; /* End of list */
subtree[count].subtree = NULL;
return subtree;
}
/*
* create_reference_tree - Create a tree containing the names of the
* subdirectories in the directory display
* that are expanded. Caller must call
* release_reference_subtree() to destroy
* the returned tree.
*/
struct ref_st *
create_reference_tree(dirwin)
struct dirwin_st *dirwin;
{
struct ref_st *tree;
int count;
int i;
/* Count number of expanded entries in directory */
count = 0;
for (i=0; i<dirwin->nentries; i++)
if (dirwin->entries[i].level == 0 && dirwin->entries[i].expanded)
count++;
/* Allocate memory for the tree of expanded subdirectories */
tree = (struct ref_st *)XtMalloc((count+1)*sizeof(struct ref_st));
/* Record names of expanded entries */
count = 0;
for (i=0; i<dirwin->nentries; i++) {
if (dirwin->entries[i].level == 0 && dirwin->entries[i].expanded) {
tree[count].name = XtNewString(dirwin->entries[i].name);
tree[count].subtree =create_reference_subtree(&dirwin->entries[i]);
count++;
}
}
tree[count].name = NULL; /* End of list */
tree[count].subtree = NULL;
return tree;
}
/*
* release_reference_subtree - Destroy the tree created by
* create_reference_subtree() or
* create_reference_tree();
*
*/
void
release_reference_subtree(subtree)
struct ref_st *subtree;
{
int indx = 0;
while (subtree[indx].name) {
XtFree(subtree[indx].name);
release_reference_subtree(subtree[indx].subtree);
indx++;
}
XtFree((char *)subtree);
}
/*
* re_expand_subtree - Re-expand the subdirectory specified by einfo.
* "ref_tree" is a structure created by
* create_reference_subtree() that describes the
* subdirectories to re-expand. If no subdirectories
* are to be re-expanded, set "ref_tree" to NULL.
* 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. Assumes that subtree is not
* already expanded. Returns 0 if successful, 1 if
* cache was used, -3 for lost connection, -6 for
* stop button pushed, and -1 for other errors.
*/
re_expand_subtree(expand_einfo, ref_tree, cstore_ok, cfetch_ok)
struct entry_info **expand_einfo;
struct ref_st *ref_tree;
int cstore_ok;
int cfetch_ok;
{
struct dirwin_st *dirwin = (*expand_einfo)->dirwin;
int expand_index = (*expand_einfo)->indx;
char *path;
int retval;
char *true_path;
struct sl_struct *dlist;
int start_index;
struct entry_info *new_entries;
int level;
int width;
struct entry_info *einfo;
int i;
int j;
int count;
int indx;
char msg[MAXPATHLEN+30];
int used_cache = False;
/* Determine true path of directory */
path = entry_to_full_path(*expand_einfo);
retval = determine_true_path(dirwin->host, path, True, cstore_ok, cfetch_ok,
&true_path);
switch (retval) {
case -1:
sprintf(msg, "Unable to expand directory subtree %s.", path);
record_warning(msg);
case -3:
case -6:
XtFree(path);
return retval;
}
XtFree(path);
/* Get directory list */
retval = get_dirlist(dirwin->host, true_path, TREE, dirwin->dotfiles_mode,
cstore_ok, cfetch_ok, &dlist);
switch (retval) {
case -1:
sprintf(msg, "Unable to expand directory subtree %s.", path);
record_warning(msg);
case -3:
case -6:
XtFree(true_path);
return retval;
case 1:
used_cache = True;
}
XtFree(true_path);
/* Allocate space to hold directory entry info */
new_entries = (struct entry_info *)XtMalloc(
(dirwin->nentries+dlist->nentries)*sizeof(struct entry_info));
start_index = (*expand_einfo)->indx+1;
bcopy(dirwin->entries, new_entries,
start_index*sizeof(struct entry_info));
bcopy(&dirwin->entries[start_index],
&new_entries[start_index+dlist->nentries],
(dirwin->nentries-start_index)*sizeof(struct entry_info));
XtFree((char *)dirwin->entries);
dirwin->entries = new_entries;
dirwin->nentries += dlist->nentries;
for (i=start_index+dlist->nentries; i<dirwin->nentries; i++)
dirwin->entries[i].indx = i;
level = dirwin->entries[expand_index].level+1;
dirwin->entries[expand_index].expanded = True;
/* Adjust entry pointer */
*expand_einfo = &dirwin->entries[expand_index];
/* Save information about directory entries */
for (i=0; i<dlist->nentries; i++) {
einfo = &dirwin->entries[start_index+i];
parse_short_entry(hinfo[dirwin->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;
einfo->state = UNSELECTED;
einfo->indx = start_index+i;
einfo->level = level;
einfo->dirwin = dirwin;
einfo->expanded = False;
dirwin->max_entry_width = MAX(dirwin->max_entry_width, width);
}
/* Re-expand subdirectories. Be super careful of recursion here! */
if (ref_tree) {
count = 0;
indx = start_index;
while (count < dlist->nentries) {
if (dirwin->entries[indx].level == level) {
count++;
if (dirwin->entries[indx].type == DIRECTORY_TYPE) {
einfo = &dirwin->entries[indx];
for (j=0; ref_tree[j].name; j++)
if (!strcmp(einfo->name, ref_tree[j].name)) {
retval = re_expand_subtree(&einfo,
ref_tree[j].subtree, cstore_ok, cfetch_ok);
if (retval < 0) {
release_array_list(dlist);
return retval;
}
if (retval == 1)
used_cache = True;
break;
}
}
}
indx++;
}
}
/* Free memory */
release_array_list(dlist);
if (used_cache)
return 1;
else
return 0;
}
/*
* re_expand_tree - Refresh the directory being displayed in tree
* layout mode in the specified directory window.
* 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, 1 if
* cache was used, -3 for lost connection, -6 for
* stop button pressed, and -1 for other errors.
*/
re_expand_tree(dirwin, cstore_ok, cfetch_ok)
struct dirwin_st *dirwin;
int cstore_ok;
int cfetch_ok;
{
int retval;
struct sl_struct *dlist;
int width;
struct entry_info *einfo;
int i;
int j;
int count = 0;
int indx;
struct ref_st *ref_tree;
char *anchor_rel_path;
int indx1;
char msg[MAXPATHLEN+30];
int used_cache = False;
/* This could take some time */
use_busy_cursor();
/* Get directory list */
retval = get_dirlist(dirwin->host, dirwin->dirname, TREE,
dirwin->dotfiles_mode, cstore_ok, cfetch_ok, &dlist);
switch (retval) {
case -1:
sprintf(msg, "Unable to expand directory tree %s.", dirwin->dirname);
record_warning(msg, dirwin->w_shell);
case -3:
case -6:
restore_prev_cursor();
return retval;
case 1:
used_cache = True;
}
/* Remember vertical scrollbar position */
if (dirwin->nentries) {
indx1 = dirwin->first_visible_row;
anchor_rel_path = entry_to_rel_path(&dirwin->entries[indx1]);
} else
anchor_rel_path = NULL;
/* Remember which subdirectories are expanded */
ref_tree = create_reference_tree(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 */
for (i=0; i<dlist->nentries; i++) {
einfo = &dirwin->entries[i];
parse_short_entry(hinfo[dirwin->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;
einfo->state = UNSELECTED;
einfo->level = 0;
einfo->dirwin = dirwin;
einfo->expanded = False;
einfo->indx = i;
dirwin->max_entry_width = MAX(dirwin->max_entry_width, width);
}
/* Re-expand the subdirectories. Be super careful of recursion! */
count = 0;
indx = 0;
while (count < dlist->nentries) {
if (dirwin->entries[indx].level == 0) {
count++;
if (dirwin->entries[indx].type == DIRECTORY_TYPE) {
einfo = &dirwin->entries[indx];
for (j=0; ref_tree[j].name; j++)
if (!strcmp(einfo->name, ref_tree[j].name)) {
retval = re_expand_subtree(&einfo, ref_tree[j].subtree,
cstore_ok, cfetch_ok);
if (retval < 0) {
release_array_list(dlist);
release_reference_subtree(ref_tree);
if (anchor_rel_path)
XtFree(anchor_rel_path);
return retval;
}
if (retval == 1)
used_cache = True;
break;
}
}
}
indx++;
}
/* Release memory */
release_array_list(dlist);
release_reference_subtree(ref_tree);
/* Perform geometry calculations for directory display */
calc_dirwin_geometry(dirwin);
/* Redraw changed part of directory display */
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);
}
update_dir_controls();
restore_prev_cursor();
if (used_cache)
return 1;
else
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1