home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w055 / 4.ddi / SOURCES.LIF / DTREE.PEL < prev    next >
Encoding:
Text File  |  1990-09-27  |  15.4 KB  |  633 lines

  1. # $Header:   P:/source/ppee/macros/dtree.pev   1.2   20 Sep 1990 13:43:14   ericj  $
  2.  
  3. ##############################################################################
  4. #
  5. #           Sage Software - POLYTRON Division
  6. #             1700 NW 167th Place
  7. #               Beaverton, OR 97006
  8. #
  9. #   Copyright 1990, Sage Software, Inc.
  10. #
  11. #   Permission is hereby granted for licensed users of Sage Professional
  12. #   Editor and PolyAwk to copy and modify this source code for their own
  13. #   personal use.  These derivative works may be distributed only to other
  14. #   licensed Sage Professional Editor and PolyAwk users.  All other usage
  15. #   is prohibited without express written permission from Sage Software.
  16. #
  17. ##############################################################################
  18.  
  19. #### $Workfile:   dtree.pel  $: 
  20. #
  21. # Build a tree structure of the given directory
  22. #
  23.  
  24.  
  25.  
  26.  
  27. local file_list[]       # list of files in current directory
  28. local file_selection    # current file selected to be edited, if any
  29. local dir_selection     # current directory highlighted in tree
  30.  
  31. local new_eol_str = "" # new eol string in file list buffer
  32.  
  33.  
  34. local tree_winid = 0;
  35. local tree_keymap
  36. local tree_buffer
  37. local tree_drive
  38. local tree_cwd
  39. global tree_lines;
  40.  
  41. local tree_array[];
  42.  
  43.  
  44.  
  45. ## tree
  46. #
  47. #  drv - Specified the drive/path for which to build a directory tree of.
  48. #        If drv is not specified, the current drive is used (from the root on).
  49. #
  50. #  A tree diagram of the directory structure is constructed an inserted into
  51. #  a buffer.  Once displayed, the tree can be used to changed directories and
  52. #  display contents of.
  53. #
  54. #  Once displayed, the following keystrokes are valid:
  55. #  <ESC>        - return to caller
  56. #  <DOWN>       - goto next directory in tree
  57. #  <UP>         - goto previos directory in tree
  58. #  <TAB>        - display the contents of the current directory selected
  59. #  <ENTER>      - make the directory selected the current working directory
  60. #  <PGUP>       - goto previous page in directory tree
  61. #  <PGDN>       - goto next page in directory tree
  62. #  <LEFT_PRESS>    - select directory under mouse
  63. #  <LEFT_CLICK> - display the contents of the current directory selected
  64. #
  65. function dtree( drv ){
  66.     local tree_win_height = display_height - 6;
  67.     local tree_win_width = 35;
  68.     local tree_win_x0 = 0;
  69.     local tree_win_y0 = 3;
  70.     local save_window = current_window;
  71.     local save_buffer = current_buffer;
  72.     local eolstr = default_buffer_eol_string;
  73.     local cdrive = (argcount() == 1 ? trim(ltrim(drv)) : dos_drive());
  74.     local level;
  75.     local valid_drv = TRUE;
  76.     local fmode;
  77.  
  78.     init_menu_colors();
  79.     file_selection = ""
  80.  
  81.  
  82.     # If the tree window doesn't exist create one.
  83.     #
  84.     if (!tree_winid) {
  85.         current_window =
  86.         tree_winid = create_factory_window( tree_win_x0, \
  87.             tree_win_y0, \
  88.             tree_win_width, \
  89.             tree_win_height, \
  90.             WINDOW_BORDER + WINDOW_SYSTEM);
  91.  
  92.         color_text = color_border = BAR_COLOR
  93.         color_highlight = HBAR_COLOR;
  94.  
  95.         visible_end_buffer = ""
  96.         visible_tabs = ""
  97.         visible_virtual_lines   = ""
  98.  
  99.         # hide the window until all other messages have been
  100.         # put on the screen
  101.         #
  102.         hide_window( tree_winid );
  103.     }
  104.  
  105.     # if the tree buffer doesn't exist create one.
  106.     #
  107.     if (!tree_buffer){
  108.         tree_drive = " ";
  109.         # create a new buffer to put the filenames into
  110.         default_buffer_eol_string = new_eol_str
  111.         tree_buffer =    \
  112.             create_buffer( "", "", BUFFER_SYSTEM + BUFFER_NO_UNDO )
  113.         default_buffer_eol_string = eolstr;
  114.     }
  115.  
  116.     attach_window_buffer( tree_winid, tree_buffer );
  117.  
  118.     # if the tree keymap doesn't exists create one.
  119.     #
  120.     if (!tree_keymap) {
  121.         tree_keymap = create_keymap(empty_keymap)
  122.         push_keymap(tree_keymap)
  123.  
  124.         assign_key( "<ESC>",  "process_end" );
  125.         assign_key( "<down>", "tree_down 1" );
  126.         assign_key( "<up>",   "tree_up 1" );
  127.         assign_key( "<TAB>",  "tree_expand" );
  128.         assign_key( "<ENTER>","tree_chdir" );
  129.         assign_key( "<PGUP>", "tree_up " tree_win_height - 2 );
  130.         assign_key( "<PGDN>", "tree_down " tree_win_height - 2 );
  131.  
  132.         assign_key( "#61440", "tree_mouse_key" )    # left press
  133.         assign_key( "#62976", "tree_mouse_key" )    # left click
  134.  
  135.  
  136.         pop_keymap();
  137.     }
  138.  
  139.  
  140.  
  141.     #
  142.     # validate the drive and path given by first checking to see
  143.     # if a valid drive was provided (if any) and then ensuring
  144.     # that the path is valid.
  145.     #
  146.     fmode = 0;
  147.     if (index( cdrive, ":" )) {
  148.         fmode = 1;            # a drive is specified
  149.         drv = dos_drive();
  150.         if ( !dos_drive( cdrive ))
  151.             valid_drv = FALSE;
  152.         dos_drive( drv );
  153.     }
  154.  
  155.  
  156.     # if the drive/path is valid so far, check to see if it is valid
  157.     #
  158.     if (valid_drv) {
  159.         cdrive = buildpath( cdrive "\\" );
  160.         if ( !(fmode && length(cdrive)==3) )
  161.             #
  162.             # in DOS, filemode() doesn't always work 
  163.             # on a network directory, so use filetime()
  164.             #
  165.             if ( filetime( trim(cdrive, "\\")) <= 0)
  166.                 valid_drv = FALSE;
  167.     }
  168.  
  169.  
  170.     # if still valid, read the directory structure for the path
  171.     #
  172.     if (valid_drv) {
  173.         cdrive = trim( cdrive, "\\" );
  174.         push_keymap(tree_keymap)
  175.  
  176.  
  177.         # if the drive/path is the same as last time, use the
  178.         # previous reading, otherwise create a new one.
  179.         #
  180.         if (tree_drive != cdrive){
  181.  
  182.             # delete all references to previous read
  183.             #
  184.             tree_unmark();
  185.             tree_drive = cdrive;
  186.             delete( tree_array )
  187.             delete( tree_lines )
  188.  
  189.             # delete buffer contents
  190.             #
  191.             goto_buffer_bottom();
  192.             drop_anchor();
  193.             goto_buffer_top()
  194.             delete_chars();
  195.  
  196.             # read all of the directory names and store
  197.             # in an array.
  198.             #
  199.             message( "Scanning directories..." );
  200.             build_tree( 0, cdrive )
  201.  
  202.             # Actually insert the names of the directories
  203.             # into the tree_buffer and format them using
  204.             # vertical bars to designate hierarchy structure.
  205.             #
  206.             message( "Constructing tree..." );
  207.             current_window = tree_winid;
  208.             current_buffer = tree_buffer;
  209.             tree_lines[ current_line ] =  cdrive;
  210.             insert_string( " " cdrive "\\\n" );
  211.             create_tree_graph( 0, cdrive, " " );
  212.             backspace();
  213.  
  214.             goto_buffer_top();
  215.             tree_mark_cwd( cdrive );
  216.         }
  217.  
  218.         current_window = tree_winid;
  219.         current_buffer = tree_buffer;
  220.         restore_window();
  221.  
  222.         message( "Scanning complete." );
  223.  
  224.         display_update();
  225.         process_begin();
  226.         pop_keymap();
  227.     } else {
  228.         notify( "invalid path specification '" cdrive "'." );
  229.     }
  230.  
  231.     if (window_valid(save_window)) {
  232.         current_window = save_window;        # restore original window.
  233.         current_buffer = save_buffer;        # restore original buffer.
  234.     }
  235.  
  236.     # Don't worry about hiding the window, just delete it and
  237.     # we'll create it again later.
  238.     #
  239.     delete_window( tree_winid );
  240.     tree_winid = 0;
  241.  
  242.     display_update();    # !!?? this shouldn't have to be here but there is
  243.                         # a bug in the windows code which leaves a
  244.                         # highlight on the screen
  245.  
  246.     if (file_selection)
  247.         edit_file( file_selection );
  248.  
  249. }
  250.  
  251.  
  252.  
  253.  
  254. ## build_tree
  255. #
  256. #  Build the tree structure by reading all or the directories and insert
  257. #  them into the tree_array. 
  258. #
  259. #  build_tree is called recursively to collect all of the directory names
  260. #
  261. #  tree_array is a 2 dimensional array containing the path and directory name
  262. #    dimension
  263. #       1      - <tree level 0..n> " " <directory path>
  264. #       2      - <directory name>
  265. #
  266. #
  267. function build_tree( level, dir_path ){
  268.     local dname;
  269.     
  270.     dname = findfirst( dir_path "\\*.*" , _SUBDIR );
  271.     while (dname) {
  272.         tree_array[ level " " dir_path ][ dname ] = 0;
  273.         dname = findnext();
  274.     }
  275.  
  276.     # don't include the "." or "..", if any
  277.     #
  278.     delete( tree_array[ level " " dir_path ][ "."  ] )
  279.     delete( tree_array[ level " " dir_path ][ ".." ] )
  280.  
  281.     # recurse through each directory
  282.     #
  283.     for (dname in tree_array[ level " " dir_path ])
  284.         build_tree( level + 1, dir_path "\\" dname );
  285. }
  286.  
  287.  
  288.  
  289.  
  290. ## create_tree_graph
  291. #
  292. #  Create a tree graph by traversing the tree_array array and extracting each
  293. #  level directories.
  294. #
  295. function create_tree_graph( level, dir_path, p_pattern ){
  296.     local dname;
  297.     local last_dname;
  298.  
  299.     # Insert all of the directories into a list but don't process
  300.     # the last directory at each level.
  301.     #
  302.     for (dname in tree_array[ level " " dir_path ]) {
  303.         if (last_dname) {
  304.             tree_lines[ current_line ] = dir_path "\\" last_dname;
  305.             insert_string( p_pattern "├──" last_dname "\n" );
  306.             create_tree_graph( level + 1, 
  307.                 tree_lines[ current_line - 1] ,
  308.                 p_pattern "│  ");
  309.         }
  310.         last_dname = dname;
  311.     }
  312.  
  313.     # Process the last directory at each level by inserting a closing
  314.     # graph angle before the directory name.
  315.     #
  316.     if (last_dname) {
  317.         tree_lines[ current_line ] = dir_path "\\" last_dname;
  318.         insert_string( p_pattern "└──" last_dname "\n" );
  319.         create_tree_graph( level + 1, 
  320.             tree_lines[ current_line - 1],
  321.             p_pattern "   ");
  322.     }
  323. }
  324.  
  325.  
  326. function tree_down( cnt ){
  327.     tree_unmark();
  328.     down( cnt );
  329.     tree_mark();
  330. }
  331.  
  332. function tree_up( cnt ){
  333.     tree_unmark();
  334.     up( cnt );
  335.     tree_mark();
  336. }
  337.  
  338.  
  339. function tree_mark(){
  340.     goto_bol();
  341.     search( "[^ " chr(179) chr(192) chr( 195 ) chr( 196 ) "]", 
  342.         SEARCH_REGEX + SEARCH_FORWARD )
  343.     save_position();
  344.     goto_eol();
  345.     drop_anchor();
  346.     restore_position( 1 );
  347. }
  348.  
  349. function tree_unmark(){
  350.     raise_anchor();
  351. }
  352.  
  353.  
  354. function tree_mark_cwd( drv ){
  355.     local level;
  356.  
  357.     tree_cwd = getcwd( drv );    # contains a trailing "\"
  358.  
  359.     # removed trailing "\"
  360.     tree_cwd = substr( tree_cwd, 0, length( tree_cwd ) - 1 ); 
  361.     tree_mark();
  362. }
  363.  
  364.  
  365.  
  366. function tree_expand(){
  367.  
  368.  
  369.     if (tree_lines[ current_line ]) {
  370.         message( "Reading directory: %s", tree_lines[ current_line ] "\\" );
  371.         file_selection = ""
  372.         directory_list( dir_selection = tree_lines[ current_line ] "\\" );
  373.         message( "Current directory: %s", getcwd() );
  374.         if (file_selection)
  375.             process_end()
  376.         dir_selection = ""
  377.     } else {
  378.         beep();
  379.     }
  380. }
  381.  
  382.  
  383. function tree_mouse_key(){
  384.     local x = -1;
  385.     local y = -1;
  386.     local pos;
  387.  
  388.     if (window_contains( mouse_event_x, mouse_event_y, tree_winid )){
  389.         pos = mouse_position( 1 );
  390.  
  391.         if ( pos == MOUSE_IN_TEXT ){
  392.             do {
  393.                 if ((x != mouse_display_x) || (y != mouse_display_y)){
  394.                     tree_unmark();
  395.                     current_line = mouse_display_y - window_text_y0 + window_first;
  396.                     tree_mark();
  397.                     display_update();
  398.                     x = mouse_display_x;
  399.                     y = mouse_display_y - window_y0 - window_height;
  400.                 }
  401.             } while ( and(mouse_buttons, LEFT_BUTTON) );
  402.         } else if (and(pos,MOUSE_N) || and(pos,MOUSE_S)){
  403.             left_press( 1 );
  404.         }
  405.  
  406.         if (current_key == LEFT_CLICK)
  407.             tree_expand();
  408.     }
  409. }
  410.  
  411.  
  412.  
  413. function tree_chdir(){
  414.     if (tree_lines[ current_line ]) {
  415.         message( "Current directory: %s", tree_lines[ current_line ] "\\" );
  416.         chdir( tree_lines[ current_line ] );
  417.         tree_expand();
  418.     } else {
  419.         beep();
  420.     }
  421. }
  422.  
  423. #---------------------------------------------------------#
  424.  
  425.  
  426.  
  427.  
  428. ## directory_list
  429. #
  430. #  Create a window and display the contents of the specified directory.
  431. #  Once displayed, the following keystrokes are valid:
  432. #
  433. #  <ENTER>         - Edit the item highlighted
  434. #  <LEFT_RELEASE>  - Edit the item highlighted
  435. #  <UP>            - Select previous item in list
  436. #  <DOWN>          - Select next item in list
  437. #  <ESC>           - Return without setting file_selection
  438. #  <PGUP>          - List previous page of items
  439. #  <PGDN>          - List next page of items
  440. #
  441. #  Upon return, the variable file_selection will be set to the selected
  442. #  item, otherwise "".
  443. #
  444. function directory_list( dirpath ){
  445.     local dirlist_keymap            # keymap used while directory is displayed
  446.     local dirlist_cwd = ""          # current directory displayed
  447.     local dirlist_win_height = display_height - 10;
  448.     local dirlist_win_width = 51;
  449.     local dirlist_win_x0 = 20;
  450.     local dirlist_win_y0 = 5;
  451.     local fname_pattern = "*.*"
  452.     local save_window = current_window;
  453.     local save_buffer = current_buffer;
  454.     local eolstr = default_buffer_eol_string;
  455.  
  456.     #
  457.     # get the directory specified if any, otherwise use the cwd
  458.     #
  459.     if (argcount())
  460.         dirlist_cwd = dirpath;
  461.  
  462.  
  463.     # create the window to display the directory file list
  464.     #
  465.     current_window = create_factory_window( dirlist_win_x0, \
  466.         dirlist_win_y0, \
  467.         dirlist_win_width, \
  468.         dirlist_win_height, \
  469.         WINDOW_BORDER + WINDOW_SB_RIGHT + WINDOW_SYSTEM);
  470.  
  471.     color_text = color_border = BAR_COLOR
  472.     color_highlight = HBAR_COLOR;
  473.  
  474.     visible_end_buffer = ""
  475.     visible_tabs = ""
  476.      visible_virtual_lines  = "              │         │";
  477.  
  478.  
  479.     # create a new buffer to put the filenames into
  480.     default_buffer_eol_string = new_eol_str
  481.     current_buffer =    \
  482.         create_buffer( "", "", BUFFER_SYSTEM + BUFFER_NO_UNDO )
  483.     default_buffer_eol_string = eolstr;
  484.     buffer_tabs = "11 15"
  485.  
  486.     attach_window_buffer( current_window, current_buffer );
  487.  
  488.  
  489.  
  490.     # read the contents of the directory into the current buffer
  491.     #
  492.     if ( dirlist_read_directory( dirlist_cwd fname_pattern ) ) {
  493.         dirlist_keymap = create_keymap(empty_keymap)
  494.         push_keymap(dirlist_keymap)
  495.  
  496.         assign_key( "<ESC>",  "process_end" );
  497.         assign_key( "<down>", "dirlist_down 1" );
  498.         assign_key( "<up>",   "dirlist_up 1" );
  499.         assign_key( "<pgdn>", "dirlist_down " dirlist_win_height - 2);
  500.         assign_key( "<pgup>", "dirlist_up " dirlist_win_height - 2);
  501.         assign_key( "<ENTER>","dirlist_enter" );
  502.         assign_key( "#61440", "menu_mouse_key" )    # left press
  503.         assign_key( "#62976", "menu_mouse_key" )    # left click
  504.  
  505.         drop_anchor( LINE_SELECTION )
  506.  
  507.         # begin processing withing the directory listing
  508.         #
  509.         process_begin();
  510.         pop_keymap();
  511.         delete_keymap( dirlist_keymap );
  512.     } else {
  513.         # the directory read failed
  514.         #
  515.         beep();
  516.     }
  517.  
  518.     delete_buffer();
  519.     delete_window();
  520. }
  521.  
  522.  
  523.  
  524. ## dirlist_read_directory
  525. #
  526. #  Read all of the normal files using the fname_pattern specified (which
  527. #  contains the full path with the pattern) and insert the name, size, time 
  528. #  and date string into the current buffer
  529. #
  530. function dirlist_read_directory( fname_pattern ){
  531.     local find_flags
  532.     local fname
  533.     local i;
  534.     local orig_name
  535.  
  536.     find_flags = _NORMAL    # include all normal files
  537.  
  538.     delete( file_list )
  539.  
  540.     fname = findfirst( fname_pattern, find_flags );
  541.     fname = path_fname( fname ) path_ext( fname )
  542.  
  543.     if (!fname)
  544.         return FALSE;
  545.  
  546.  
  547.     # read all of the filenames out of the directory specified
  548.     # and format them.
  549.     #
  550.     while (fname) {
  551.  
  552.         orig_name = fname
  553.         # format the filename string so that no .'s  are displayed
  554.         # and so the extension is separated from the basename.
  555.         #
  556.         if (!sub( "\\.", "\t", fname ))
  557.             fname = fname "\t"
  558.  
  559.         fname = sprintf( "%-s\t│%9.9ld│%s", toupper( fname ), \
  560.             filesize(), ctime(filetime()));
  561.         file_list[ fname ] = orig_name;
  562.  
  563.         fname = findnext()
  564.     }
  565.  
  566.  
  567.     # insert new file names into the buffer
  568.     #
  569.     for (i in file_list)
  570.         insert_string( i new_eol_str )
  571.  
  572.     backspace();       # remove the last newline character
  573.     goto_buffer_top();
  574.     return TRUE;
  575. }
  576.  
  577.  
  578. ## process a down key press from within a menu
  579. #
  580. global function dirlist_down( lines ) {
  581.  
  582.     if ( down( lines )) {
  583.         #
  584.         # redisplay the highlight on the new selection
  585.         #
  586.         raise_anchor()
  587.         drop_anchor( LINE_SELECTION )
  588.     }
  589. }
  590.  
  591.  
  592.  
  593. ## process an up key press from within a menu
  594. #
  595. global function dirlist_up( lines ){
  596.  
  597.     if ( up( lines )) {
  598.         #
  599.         # redisplay the highlight on the new selection
  600.         #
  601.         raise_anchor()
  602.         drop_anchor( LINE_SELECTION )
  603.     }
  604. }
  605.  
  606. ## process a home key press from within a menu
  607. #
  608. global function dirlist_home(){
  609.  
  610.     raise_anchor()
  611.     goto_buffer_top();
  612.     drop_anchor( LINE_SELECTION )
  613. }
  614.  
  615. ## process an end key press from within a menu
  616. #
  617. global function dirlist_end(){
  618.  
  619.     raise_anchor()
  620.     goto_buffer_bottom();
  621.     drop_anchor( LINE_SELECTION )
  622. }
  623.  
  624. function dirlist_enter(){
  625.     file_selection = dir_selection file_list[ read_buffer() ];
  626.     process_end();
  627. }
  628.  
  629.  
  630.  
  631. #---------------------------------------------------------#
  632.  
  633.