/***************************************************************************/ /***************************************************************************/ /* */ /* (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 #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; inentries; 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; ientries[i].name); XtFree(dirwin->entries[i].info); } XtFree((char *)dirwin->entries); dirwin->entries = new_entries; dirwin->nentries -= count; for (i=start_index; inentries; 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; inentries; 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; inentries; 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; inentries; 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; inentries; 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; inentries; 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; inentries; 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; inentries; 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; inentries; 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; inentries; 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; }