home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 484 / NPED.ZIP / FILEMAN.PRG < prev    next >
Text File  |  1993-07-08  |  36KB  |  1,186 lines

  1. /***
  2. *  Fileman.prg
  3. *  Sample file manager that can be linked into your programs.
  4. *
  5. *  Copyright (c) 1990, Nantucket Corp.  All rights reserved.
  6. *  David R. Alison
  7. *
  8. *  Note:   Compile with /W /N switches.
  9. *
  10. *  Syntax:
  11. *          FileMan( <nRowTop>, <nColumnTop>, <nRowBottom>,
  12. *                   [<cColorString>],
  13. *                   [<cDefaultPath>] ) -> cDOSFileName
  14. *  Arguments:
  15. *          <nRowTop>, <nColumnTop> and <nRowBottom> are the upper left
  16. *          and lower window coordinates for FileMan().
  17. *
  18. *          <cColorString> is the optional color string to be used for
  19. *          FileMan().  Files are displayed in the standard color,
  20. *          the highlight is in enhanced color and hidden/system files
  21. *          are displayed in the unselected color.  If <cColorString> is
  22. *          not specified, the current default color string will be used.
  23. *
  24. *          <cDefaultPath> is an optional initial file path.  For example,
  25. *          the following FileMan() call:
  26. *
  27. *             FileMan( 1, 5, 18, "C:\DBFILES\*.EXE" )
  28. *
  29. *          displays a FileMan() file chooser from row 1, column 5 to
  30. *          row 18.  The FileMan() menu only displays the files in the
  31. *          C:\DBFILES\ directory that have an EXE extension.
  32. *
  33. *  Returns:
  34. *          FileMan() returns the full path and file name of the file
  35. *          selected.  For example, selecting DBU.EXE from the
  36. *          \DBFILES directory on the C: drive would result in a return
  37. *          character string of:
  38. *
  39. *             "C:\DBFILES\DBU.EXE"
  40. *
  41. *          If no file was selected a null ("") string is returned.
  42. *
  43. *  Description:
  44. *          FileMan() is a high-level function that displays a list of
  45. *          files in a scrolling pick list.  It is best implemented when
  46. *          a user is required to select a file from a disk and perform
  47. *          some type of action on it.
  48. *
  49. *          Navigating through the list of files is accomplished by the
  50. *          up and down arrow keys.  The left and right arrow keys are
  51. *          used to move through the menu options.  Pressing Return will
  52. *          activate the highlighted menu option for the file that is
  53. *          highlighted from the pick list.  The Copy and
  54. *          Delete options can also be performed on tagged files.  Tagging
  55. *          a file is accomplished by pressing the Space Bar while the
  56. *          file is highlighted.  A "tag all" toggle, F5, can be used to
  57. *          tag and untag all the files in the current pick list.
  58. *
  59. *          The menu items in FileMan() are:
  60. *
  61. *          Look, Copy, Rename, Delete, Print and Options
  62. *
  63. *          a brief description of each follows:
  64. *
  65. *          Look:    Views the currently highlighted file in a "raw text"
  66. *                   window, allowing the user to scroll though it.  If
  67. *                   their is a file viewer for the extension of that
  68. *                   file, a file viewer is loaded and the file is viewed
  69. *                   in it's native form.  This version has viewers for:
  70. *                   DBF (Clipper/dBASE database file), NTX (Clipper index),
  71. *                   LBL (Label form) and FRM (Report form).
  72. *
  73. *          Copy:    Copies the selected file(s) to a specific location,
  74. *                   either on another drive or in another directory.
  75. *
  76. *          Rename:  Renames the selected file to a new name.
  77. *
  78. *          Delete:  Deletes the selected file(s).
  79. *
  80. *          Print:   Prints the selected files to the printer in raw form.
  81. *
  82. *          Options: Displays a second menu with choices for sorting the
  83. *                   files, a call to internal help and an "about
  84. *                   FileMan()" screen.
  85. */
  86.  
  87. #include "Fileman.ch"
  88. #include "Directry.ch"
  89. #include "Inkey.ch"
  90. #include "Memoedit.ch"
  91. #include "Achoice.ch"
  92.  
  93. STATIC aFileMan, aFileList
  94. STATIC hScrollBar, nMenuItem, nTagged
  95. STATIC nEl, nRel, lReloadDir, nFileItem
  96. MEMVAR GetList
  97.  
  98. /***
  99. *  FileMan( <nRowTop>, <nColumnTop>, <nRowBottom>, 
  100. *     [<cColorString>], [<cDefaultPath>] ) --> cDOSFileName
  101. *
  102. */
  103. FUNCTION FileMan( nRowTop, nColumnTop, nRowBottom, ;
  104.                   cColorString, cDefaultPath )
  105.    LOCAL lSetScore
  106.  
  107.    // Set the default values
  108.    nMenuItem   := 1
  109.    nTagged     := 0
  110.    nFileItem   := 1
  111.    nEl         := 1
  112.    nRel        := 1
  113.    lReloadDir  := .T.
  114.    aFileMan    := {}
  115.    aFileList   := {}
  116.  
  117.    // Create the array
  118.    aFileMan := ARRAY( FM_ELEMENTS )
  119.  
  120.    // Resolve parameters
  121.    IF nRowTop = NIL
  122.       nRowTop := 0
  123.    ELSE
  124.       IF nRowTop > (MAXROW() - 7)
  125.          nRowTop := MAXROW() - 7
  126.       ENDIF
  127.    ENDIF
  128.    aFileMan[ FM_ROWTOP ] := nRowTop
  129.  
  130.    IF nColumnTop = NIL
  131.       nColumnTop := 0
  132.    ELSE
  133.       IF nColumnTop > (MAXCOL() - 52)
  134.          nColumnTop := MAXROW() - 52
  135.       ENDIF
  136.    ENDIF
  137.    aFileMan[ FM_COLTOP ] := nColumnTop
  138.  
  139.    IF nRowBottom = NIL
  140.       nRowBottom := 0
  141.    ELSE
  142.       IF nRowBottom > MAXROW()
  143.          nRowBottom := MAXROW()
  144.       ENDIF
  145.    ENDIF
  146.    aFileMan[ FM_ROWBOTTOM ] := nRowBottom
  147.    aFileMan[ FM_COLBOTTOM ] := nColumnTop + 51
  148.  
  149.    // Color string for FileMan()
  150.    IF cColorString = NIL
  151.       cColorString := SETCOLOR()
  152.    ENDIF
  153.    aFileMan[ FM_COLOR ] := cColorString
  154.  
  155.    // Initial path information
  156.    IF cDefaultPath = NIL
  157.    // cDefaultPath := "\" + CURDIR() + "\*.*"  // original
  158.       cDefaultPath := CURDIR() + "\*.*"        // using Funck(y)'s CurDir()
  159.       cDefaultPath := STRTRAN( cDefaultPath, "\\", "\" ) 
  160.    ENDIF
  161.    aFileMan[ FM_PATH ] := cDefaultPath
  162.  
  163.    // Save the old color
  164.    aFileMan[ FM_OLDCOLOR ] := SETCOLOR( aFileMan[ FM_COLOR ] )
  165.  
  166.    // Save the old work area
  167.    aFileMan[ FM_OLDSELECT ] := SELECT()
  168.  
  169.    // Set the scoreboard
  170.    lSetScore := SET( _SET_SCOREBOARD, .F. )
  171.  
  172.    // Save the screen
  173.    aFileMan[ FM_OLDSCREEN ] := SAVESCREEN( aFileMan[ FM_ROWTOP    ], ;
  174.                                            aFileMan[ FM_COLTOP    ], ;
  175.                                            aFileMan[ FM_ROWBOTTOM ], ;
  176.                                            aFileMan[ FM_COLBOTTOM ] )
  177.  
  178.    CreateScreen()                   // Create the initial screen, etc.
  179.    GetFiles()                       // Call the actual file chooser
  180.  
  181.    // Restore the screen
  182.    RESTSCREEN( aFileMan[ FM_ROWTOP    ], ;
  183.                aFileMan[ FM_COLTOP    ], ;
  184.                aFileMan[ FM_ROWBOTTOM ], ;
  185.                aFileMan[ FM_COLBOTTOM ], ;
  186.                aFileMan[ FM_OLDSCREEN ] )
  187.    // Restore the color
  188.    SetColor( aFileMan[ FM_OLDCOLOR ] )
  189.  
  190.    // Reset the old scoreboard stuff
  191.    SET( _SET_SCOREBOARD, lSetScore )
  192.  
  193.    // Restore the work area
  194.    SELECT ( aFileMan[ FM_OLDSELECT ] )
  195.  
  196.    // Back to the real world!
  197.    RETURN( aFileMan[ FM_RETURNFILE ] )
  198.  
  199. /***
  200. *  GetFiles() --> NIL
  201. *
  202. *
  203. */
  204. STATIC FUNCTION GetFiles
  205.    LOCAL lDone       := .F.            // Primary loop point
  206.    LOCAL nCurrent    := 0              // ACHOICE() result
  207.    LOCAL nLastKey    := 0              // Last value in LASTKEY()
  208.  
  209.    DO WHILE !lDone
  210.       IF lReloadDir
  211.          nEl   := 1
  212.          nRel  := 1
  213.          IF !LoadFiles()
  214.             // A problem occurred loading the file names; tell the user
  215.             ErrorBeep()
  216.             Message( "ERROR: No files found!  Press any key..." )
  217.             INKEY( 300 )
  218.             IF YesOrNo( "Would you like to try another path? (Y/N)", "Y" )
  219.                GetNewPath( aFileMan[ FM_PATH ] )
  220.                IF LASTKEY() == K_ESC
  221.                   lDone := .T.
  222.                ELSE
  223.                   LOOP
  224.                ENDIF
  225.             ELSE
  226.                lDone := .T.
  227.             ENDIF
  228.          ELSE
  229.             lReloadDir := .F.
  230.          ENDIF
  231.       ENDIF
  232.       // Time to display the files and act on the response's
  233.       TabUpdate( hScrollBar, nEl, LEN( aFileList ), .T. )
  234.       nCurrent := ACHOICE( aFileMan[ FM_ROWTOP ] + 3, ;
  235.                            aFileMan[ FM_COLTOP ] + 2, ;
  236.                            aFileMan[ FM_ROWBOTTOM ] - 3, ;
  237.                            aFileMan[ FM_COLBOTTOM ] - 4, ;
  238.                            aFileList, .T., "ProcessKey", nEl, nRel )
  239.  
  240.       nFileItem := nCurrent
  241.       nLastKey := LASTKEY()
  242.  
  243.       DO CASE
  244.          CASE UPPER(CHR(nLastKey)) $ "LCRDPE"
  245.             // They selected a menu item ; move the highlight
  246.             nMenuItem := AT( UPPER(CHR(nLastKey)), "LCRDPE" )
  247.             DisplayMenu()
  248.  
  249.          CASE nLastKey == K_RIGHT
  250.             nMenuItem++
  251.             IF nMenuItem > 6
  252.                TONE( 900, 1 )
  253.                nMenuItem := 6
  254.             ENDIF
  255.             DisplayMenu()
  256.  
  257.          CASE nLastKey == K_LEFT
  258.             nMenuItem--
  259.             IF nMenuItem < 1
  260.                TONE( 900, 1 )
  261.                nMenuItem := 1
  262.             ENDIF
  263.             DisplayMenu()
  264.  
  265.          CASE nLastKey == K_ESC
  266.             aFileMan[ FM_RETURNFILE ] := ""
  267.             lDone := .T.
  268.  
  269.          CASE nLastKey == K_ENTER
  270.             // First let's assign the filename and path to aFileMan
  271.             aFileMan[ FM_RETURNFILE ] := ;
  272.                      SUBSTR( aFileMan[ FM_PATH ], 1, ;
  273.                      RAT( "\", aFileMan[ FM_PATH ] ) ) + ;
  274.                      TRIM( SUBSTR( aFileList[ nCurrent ], 1, 12 ) )
  275.  
  276.             // Ok, here's the biggee
  277.             DO CASE
  278.                CASE nMenuItem == MN_LOOK
  279.                   LookAtFile()
  280.  
  281.                CASE nMenuItem == MN_COPY
  282.                   CopyFile()
  283.  
  284.                CASE nMenuItem == MN_RENAME
  285.                   RenameFile()
  286.  
  287.                CASE nMenuItem == MN_DELETE
  288.                   DeleteFile()
  289.  
  290.                CASE nMenuItem == MN_PRINT
  291.                   PrintFile()
  292.  
  293.                CASE nMenuItem == MN_OPEN
  294.                   IF AT( '<dir>', aFileList[ nFileItem ] ) = 0
  295.                      lDone := .T.
  296.                   ELSE
  297.                      LookAtFile()
  298.                   ENDIF
  299.  
  300.             ENDCASE
  301.  
  302.          CASE nLastKey == K_DEL
  303.             DeleteFile()
  304.  
  305.          CASE nLastKey == K_F5
  306.             TagAllFiles()
  307.  
  308.          CASE nLastKey == K_F6
  309.             UnTagAllFiles()
  310.  
  311.          CASE nLastKey == K_SPACE
  312.             // Can't tag directories
  313.             IF AT( "D", SUBSTR( aFileList[ nCurrent ], 43, 6 ) ) == 0
  314.                IF SUBSTR( aFileList[ nCurrent ], 14, 1 ) == " "
  315.                   // It isn't tagged, let's tag it
  316.                   aFileList[ nCurrent ] := STUFF( aFileList[ nCurrent ], ;
  317.                                            14, 1, FM_CHECK )
  318.                   nTagged++
  319.                ELSE
  320.                   // It's already tagged, let's remove the check mark
  321.                   aFileList[ nCurrent ] := STUFF( aFileList[ nCurrent ], ;
  322.                                            14, 1, " " )
  323.                   nTagged--
  324.                ENDIF
  325.             ENDIF
  326.  
  327.       ENDCASE
  328.    ENDDO
  329.  
  330.    RETURN NIL
  331.  
  332. /***
  333. *  LoadFiles() --> lReturnValue 
  334. *
  335. *
  336. */
  337. STATIC FUNCTION LoadFiles
  338.    LOCAL aDirectory := {}, nItem := 0, lReturnValue := .T.
  339.    LOCAL nNumberOfItems := 0, cFileString := ""
  340.  
  341.    // Let the user know what's going on
  342.    Message( "Loading the current directory..." )
  343.    @ aFileMan[ FM_ROWTOP ] + 3, aFileMan[ FM_COLTOP ] + 2 CLEAR TO ;
  344.      aFileMan[ FM_ROWBOTTOM ] - 3, aFileMan[ FM_COLBOTTOM ] - 4
  345.  
  346.    // Load up aFileList with the current directory information
  347.    aDirectory := DIRECTORY( aFileMan[ FM_PATH ], "D" )
  348.    nNumberOfItems := IF( VALTYPE( aDirectory ) != "A", 0, LEN( aDirectory ) )
  349.    aFileList := {}                  // Wipe out the old aFileList
  350.  
  351.    // Check to see if any files actually made it
  352.    IF nNumberOfItems < 1
  353.       // Problem!
  354.       lReturnValue := .F.
  355.  
  356.    ELSE
  357.       // Let the user know what's going on
  358.       Message( "Sorting the current directory..." )
  359.  
  360.       // Sort the current aDirectory array
  361.       ASORT( aDirectory,,, { | x, y | x[ F_NAME ] < y[ F_NAME ] } )
  362.  
  363.       // Let the user know what's going on
  364.       Message( "Processing the current directory..." )
  365.  
  366.       // Now drop it into the array to be displayed with ACHOICE()
  367.       FOR nItem := 1 TO nNumberOfItems
  368.          AADD( aFileList, PADR( aDirectory[ nItem, F_NAME ], 15 ) + ;
  369.                           IF( SUBSTR( aDirectory[ nItem, F_ATTR ], ;
  370.                           1, 1 ) == "D", "   <dir>", ;
  371.                           STR( aDirectory[ nItem, F_SIZE ], 8 ) ) + "  " + ;
  372.                           DTOC( aDirectory[ nItem, F_DATE ] ) + "  " + ;
  373.                           SUBSTR( aDirectory[ nItem, F_TIME ], 1, 5) + "  " + ;
  374.                           SUBSTR( aDirectory[ nItem, F_ATTR ], 1, 4 ) + "  " )
  375.       NEXT
  376.  
  377.    ENDIF
  378.  
  379.    // Clean up the message area before we leave
  380.    Message( aFileMan[ FM_PATH ] )
  381.  
  382.    RETURN( lReturnValue )
  383.  
  384. /***
  385. *  ProcessKey( <nStatus>, <nElement>, <nRelative> ) --> nReturnValue
  386. *
  387. *
  388. */
  389. FUNCTION ProcessKey( nStatus, nElement, nRelative )
  390.    LOCAL nReturnValue := AC_CONT    // Set the default handler to continue
  391.  
  392.    // Update the global element/relative with the passed versions
  393.    nEl  := nElement
  394.    nRel := nRelative
  395.  
  396.    DO CASE
  397.    CASE nStatus == AC_IDLE
  398.       // Update the scroll bar
  399.       TabUpdate( hScrollBar, nElement, LEN( aFileList ) )
  400.       Message( aFileMan[ FM_PATH ] )
  401.  
  402.    CASE nStatus == AC_HITTOP .OR. nStatus == AC_HITBOTTOM
  403.       // Tried to go too far!
  404.       TONE( 900, 1 )
  405.  
  406.    CASE nStatus == AC_EXCEPT
  407.       // Keystroke exception
  408.       DO CASE
  409.       CASE LASTKEY() == K_ESC
  410.          nReturnValue := AC_ABORT
  411.  
  412.       CASE LASTKEY() == K_HOME
  413.          KEYBOARD CHR( K_CTRL_PGUP )
  414.          nReturnValue := AC_CONT
  415.  
  416.       CASE LASTKEY() == K_END
  417.          KEYBOARD CHR( K_CTRL_PGDN )
  418.          nReturnValue := AC_CONT
  419.  
  420.       CASE LASTKEY() == K_LEFT .OR. LASTKEY() == K_RIGHT
  421.          nReturnValue := AC_SELECT
  422.  
  423.       CASE UPPER(CHR(LASTKEY())) $ ;
  424.          "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 " .OR. ;
  425.          LASTKEY() == K_DEL .OR. LASTKEY() == K_ENTER .OR. ;
  426.          LASTKEY() == K_F5 .OR. LASTKEY() == K_F6
  427.  
  428.          nReturnValue := AC_SELECT
  429.  
  430.       ENDCASE
  431.  
  432.    ENDCASE
  433.  
  434.    RETURN (nReturnValue)
  435.  
  436. /***
  437. *  Message( cString ) --> nil
  438. *
  439. *
  440. */
  441. STATIC FUNCTION Message( cString )
  442.    LOCAL cOldColor := SETCOLOR( aFileMan[ FM_COLOR ] )
  443.    ClearMessage()
  444.    @ aFileMan[ FM_ROWBOTTOM ] - 1, aFileMan[ FM_COLTOP ] + 2 SAY ;
  445.       SUBSTR( cString, 1, (aFileMan[FM_COLBOTTOM] - aFileMan[FM_COLTOP] - 6 ))
  446.  
  447.    SETCOLOR( cOldColor )
  448.  
  449.    RETURN NIL
  450.  
  451. /***
  452. *  GetNewPath( <cPath> ) --> cNewPath
  453. *
  454. *
  455. */
  456. STATIC FUNCTION GetNewPath( cPath )
  457.    LOCAL cOldColor := SETCOLOR( aFileMan[ FM_COLOR ] )
  458.    ClearMessage()
  459.    cPath := PADR( cPath, 45 )
  460.    @ aFileMan[ FM_ROWBOTTOM ] - 1, aFileMan[ FM_COLTOP ] + 2 GET ;
  461.      cPath PICTURE "@!@S45@K"
  462.    READ
  463.  
  464.    cPath := LTRIM(TRIM(cPath))
  465.  
  466.    IF RIGHT( cPath, 1 ) == "\"
  467.       cPath += "*.*"
  468.    ENDIF
  469.    IF RIGHT( cPath, 1 ) == ":"
  470.       cPath += "\*.*"
  471.    ENDIF
  472.  
  473.    aFileMan[ FM_PATH ] := cPath
  474.  
  475.    Message( cPath )
  476.  
  477.    SETCOLOR( cOldColor )
  478.    RETURN( TRIM( cPath ) )
  479.  
  480. /***
  481. *  YesOrNo( <cMessage>, <cDefault> ) --> lYesOrNo
  482. *
  483. *
  484. */
  485. STATIC FUNCTION YesOrNo( cMessage, cDefault )
  486.    LOCAL cOldColor := SETCOLOR( aFileMan[ FM_COLOR ] )
  487.    LOCAL lYesOrNo
  488.  
  489.    @ aFileMan[ FM_ROWBOTTOM ] - 1, aFileMan[ FM_COLTOP ] + 2 SAY ;
  490.      TRIM( SUBSTR( cMessage, 1, ;
  491.          (aFileMan[FM_COLBOTTOM] - aFileMan[FM_COLTOP] - 8 )) ) GET ;
  492.          cDefault PICTURE "Y"
  493.    READ
  494.  
  495.    lYesOrNo := (UPPER( cDefault ) == "Y")
  496.    SETCOLOR( cOldColor )
  497.  
  498.    RETURN (lYesOrNo)
  499.  
  500. /***
  501. *  ClearMessage() --> NIL
  502. *
  503. *
  504. */
  505. STATIC FUNCTION ClearMessage
  506.    LOCAL cOldColor := SETCOLOR( aFileMan[ FM_COLOR ] )
  507.    @ aFileMan[ FM_ROWBOTTOM ] - 1, aFileMan[ FM_COLTOP ] + 2 CLEAR TO ;
  508.      aFileMan[ FM_ROWBOTTOM ] - 1, aFileMan[ FM_COLBOTTOM ] - 4
  509.  
  510.    SETCOLOR( cOldColor )
  511.  
  512.    RETURN NIL
  513.  
  514. /***
  515. *  ErrorBeep() --> NIL
  516. *
  517. *
  518. */
  519. STATIC FUNCTION ErrorBeep
  520.    LOCAL nCount := 0
  521.  
  522.    FOR nCount := 1 TO 2
  523.       TONE( 300, 1 )
  524.       TONE( 499, 1 )
  525.    NEXT
  526.  
  527.    RETURN NIL
  528.  
  529. /***
  530. *  CreateScreen() --> NIL
  531. *
  532. *
  533. */
  534. STATIC FUNCTION CreateScreen
  535.  
  536.    LOCAL cFrameType  := FM_SINGLEFRAME
  537.    LOCAL cBorderType := FM_SINGLEBORDER
  538.    LOCAL nRow        := 0
  539.  
  540.    // Draw the primary box
  541.    @ aFileMan[ FM_ROWTOP ], aFileMan[ FM_COLTOP ] CLEAR TO ;
  542.      aFileMan[ FM_ROWBOTTOM ], aFileMan[ FM_COLBOTTOM ]
  543.    @ aFileMan[ FM_ROWTOP ], aFileMan[ FM_COLTOP ], ;
  544.      aFileMan[ FM_ROWBOTTOM ], aFileMan[ FM_COLBOTTOM ] BOX cFrameType
  545.  
  546.    // Draw the horizontal line under the menus
  547.    @ aFileMan[ FM_ROWTOP ] + 2, aFileMan[ FM_COLTOP ];
  548.      SAY SUBSTR( cBorderType, FM_LEFT, 1 )
  549.    @ aFileMan[ FM_ROWTOP ] + 2, aFileMan[ FM_COLBOTTOM ];
  550.      SAY SUBSTR( cBorderType, FM_RIGHT, 1 )
  551.    @ aFileMan[ FM_ROWTOP ] + 2, aFileMan[ FM_COLTOP ] + 1;
  552.      SAY REPLICATE( SUBSTR( cFrameType, FM_HORIZONTAL, 1 ),;
  553.          ( aFileMan[ FM_COLBOTTOM ] - aFileMan[ FM_COLTOP ] - 1 )  )
  554.  
  555.    // Draw the vertical line next to the scroll bar
  556.    FOR nRow := (aFileMan[ FM_ROWTOP ] + 3) TO (aFileMan[ FM_ROWBOTTOM ] - 1)
  557.       @ nRow, aFileMan[ FM_COLBOTTOM ] - 2 ;
  558.         SAY SUBSTR( cFrameType, FM_VERTICAL, 1 )
  559.    NEXT
  560.    @ aFileMan[ FM_ROWTOP ] + 2, aFileMan[ FM_COLBOTTOM ] - 2 SAY ;
  561.      SUBSTR( cBorderType, FM_TOP, 1 )
  562.    @ aFileMan[ FM_ROWBOTTOM ], aFileMan[ FM_COLBOTTOM ] - 2 SAY ;
  563.      SUBSTR( cBorderType, FM_BOTTOM, 1 )
  564.  
  565.    // Draw the horizontal line under the file display area
  566.    @ aFileMan[ FM_ROWBOTTOM ] - 2, aFileMan[ FM_COLTOP ] ;
  567.      SAY SUBSTR( cBorderType, FM_LEFT, 1 )
  568.    @ aFileMan[ FM_ROWBOTTOM ] - 2, aFileMan[ FM_COLBOTTOM ] -2 ;
  569.      SAY SUBSTR( cBorderType, FM_RIGHT, 1 )
  570.    @ aFileMan[ FM_ROWBOTTOM ] - 2, aFileMan[ FM_COLTOP ] + 1 ;
  571.      SAY REPLICATE( SUBSTR( cFrameType, FM_HORIZONTAL, 1 ), ;
  572.          ( aFileMan[ FM_COLBOTTOM ] - aFileMan[ FM_COLTOP ] - 3 )  )
  573.  
  574.    // Create the scrolling thumb tab and assign it to our global static
  575.    hScrollBar := TabNew( aFileMan[ FM_ROWTOP ] + 3, ;
  576.                          aFileMan[ FM_COLBOTTOM ] - 1, ;
  577.                          aFileMan[ FM_ROWBOTTOM ] - 1, ;
  578.                          aFileMan[ FM_COLOR ], 1 )
  579.    TabDisplay( hScrollBar )
  580.  
  581.    DisplayMenu()
  582.  
  583.    RETURN NIL
  584.  
  585. /***
  586. *  DisplayMenu() --> NIL
  587. *
  588. *
  589. */
  590. STATIC FUNCTION DisplayMenu
  591.  
  592.    LOCAL cOldColor := SETCOLOR(), nCol := aFileMan[ FM_COLTOP ] + 2
  593.    LOCAL cItemName
  594.  
  595.    @ aFileMan[ FM_ROWTOP ] + 1, aFileMan[ FM_COLTOP ] + 2 SAY ;
  596.      "Look  Copy  Rename  Delete  Print  Edit"
  597.    SETCOLOR( "I" )
  598.    DO CASE
  599.    CASE nMenuItem == MN_LOOK
  600.       nCol := aFileMan[ FM_COLTOP ] + 2
  601.       cItemName := "Look"
  602.  
  603.    CASE nMenuItem == MN_COPY
  604.       nCol := aFileMan[ FM_COLTOP ] + 8
  605.       cItemName := "Copy"
  606.  
  607.    CASE nMenuItem == MN_RENAME
  608.       nCol := aFileMan[ FM_COLTOP ] + 14
  609.       cItemName := "Rename"
  610.  
  611.    CASE nMenuItem == MN_DELETE
  612.       nCol := aFileMan[ FM_COLTOP ] + 22
  613.       cItemName := "Delete"
  614.  
  615.    CASE nMenuItem == MN_PRINT
  616.       nCol := aFileMan[ FM_COLTOP ] + 30
  617.       cItemName := "Print"
  618.  
  619.    CASE nMenuItem == MN_OPEN
  620.       nCol := aFileMan[ FM_COLTOP ] + 37
  621.       cItemName := "Edit"
  622.  
  623.    ENDCASE
  624.  
  625.    @ aFileMan[ FM_ROWTOP ] + 1, nCol SAY cItemName
  626.    Message( aFileMan[ FM_PATH ] )
  627.  
  628.    SETCOLOR( cOldColor )
  629.  
  630.    RETURN NIL
  631.  
  632.  
  633. /***
  634. *    TabNew()
  635. */
  636.  
  637. STATIC FUNCTION TabNew( nTopRow, nTopColumn, nBottomRow, ;
  638.                         cColorString, nInitPosition )
  639.    // Creates a new "thumb tab" or scroll bar for the specified coordinates
  640.    LOCAL aTab := ARRAY( TB_ELEMENTS )
  641.  
  642.    aTab[ TB_ROWTOP ]    := nTopRow
  643.    aTab[ TB_COLTOP ]    := nTopColumn
  644.    aTab[ TB_ROWBOTTOM ] := nBottomRow
  645.    aTab[ TB_COLBOTTOM ] := nTopColumn
  646.  
  647.    // Set the default color to White on Black if none specified
  648.    IF cColorString == NIL
  649.       cColorString := "W/N"
  650.    ENDIF
  651.    aTab[ TB_COLOR ]     := cColorString
  652.  
  653.    // Set the starting position
  654.    IF nInitPosition == NIL
  655.       nInitPosition := 1
  656.    ENDIF
  657.    aTab[ TB_POSITION ]    := nInitPosition
  658.  
  659.    RETURN aTab
  660.  
  661.  
  662. /***
  663. *    TabDisplay()
  664. */
  665.  
  666. STATIC FUNCTION TabDisplay( aTab )
  667.    LOCAL cOldColor, nRow
  668.  
  669.    cOldColor := SETCOLOR( aTab[ TB_COLOR ] )
  670.  
  671.    // Draw the arrows
  672.    @ aTab[ TB_ROWTOP ], aTab[ TB_COLTOP ] SAY TB_UPARROW
  673.    @ aTab[ TB_ROWBOTTOM ], aTab[ TB_COLBOTTOM ] SAY TB_DNARROW
  674.  
  675.    // Draw the background
  676.    FOR nRow := (aTab[ TB_ROWTOP ] + 1) TO (aTab[ TB_ROWBOTTOM ] - 1)
  677.       @ nRow, aTab[ TB_COLTOP ] SAY TB_BACKGROUND
  678.    NEXT
  679.  
  680.    SETCOLOR( cOldColor )
  681.  
  682.    RETURN aTab
  683.  
  684.  
  685. /***
  686. *    TabUpdate()
  687. */
  688.  
  689. STATIC FUNCTION TabUpdate( aTab, nCurrent, nTotal, lForceUpdate )
  690.    LOCAL cOldColor, nNewPosition
  691.    LOCAL nScrollHeight := (aTab[TB_ROWBOTTOM]-1)-(aTab[TB_ROWTOP])
  692.  
  693.    IF nTotal < 1
  694.       nTotal := 1
  695.    ENDIF
  696.  
  697.    IF nCurrent < 1
  698.       nCurrent := 1
  699.    ENDIF
  700.  
  701.    IF nCurrent > nTotal
  702.       nCurrent := nTotal
  703.    ENDIF
  704.  
  705.    IF lForceUpdate == NIL
  706.       lForceUpdate := .F.
  707.    ENDIF
  708.  
  709.    cOldColor := SETCOLOR( aTab[ TB_COLOR ] )
  710.  
  711.    // Determine the new position
  712.    nNewPosition := ROUND( (nCurrent / nTotal) * nScrollHeight, 0 )
  713.  
  714.    // Resolve algorythm oversights
  715.    nNewPosition := IF( nNewPosition < 1, 1, nNewPosition )
  716.    nNewPosition := IF( nCurrent == 1, 1, nNewPosition )
  717.    nNewPosition := IF( nCurrent >= nTotal, nScrollHeight, nNewPosition )
  718.  
  719.    // Overwrite the old position (if different), then draw in the new one
  720.    IF nNewPosition <> aTab[ TB_POSITION ] .OR. lForceUpdate
  721.       @ (aTab[ TB_POSITION ] + aTab[ TB_ROWTOP ]), aTab[ TB_COLTOP ] SAY ;
  722.         TB_BACKGROUND
  723.       @ (nNewPosition + aTab[ TB_ROWTOP ]), aTab[ TB_COLTOP ] SAY;
  724.         TB_HIGHLIGHT
  725.       aTab[ TB_POSITION ] := nNewPosition
  726.    ENDIF
  727.  
  728.    SETCOLOR( cOldColor )
  729.  
  730.    RETURN aTab
  731.  
  732.  
  733. /***
  734. *  UpPath( <cPath> ) --> ?
  735. *
  736. *
  737. */
  738. STATIC FUNCTION UpPath( cPath )
  739.    LOCAL cFileSpec
  740.  
  741.    cFileSpec := RIGHT( cPath, LEN( cPath ) - RAT( "\", cPath ) )
  742.    cPath     := LEFT( cPath, RAT( "\", cPath ) - 1 )
  743.    cPath     := LEFT( cPath, RAT( "\", cPath ) )
  744.    cPath     += cFileSpec
  745.  
  746.    RETURN (cPath)
  747.  
  748. /***
  749. *  GetFileExtension( <cFile> ) --> cFileExtension
  750. *
  751. *
  752. */
  753. STATIC FUNCTION GetFileExtension( cFile )
  754.    RETURN( UPPER( SUBSTR( cFile, AT( ".", cFile ) + 1, 3 ) ) )
  755.  
  756. /***
  757. *  LookAtFile() --> NIL
  758. *
  759. *
  760. */
  761. STATIC FUNCTION LookAtFile
  762.    LOCAL cExtension := ""
  763.    LOCAL cOldScreen := SAVESCREEN( 0, 0, MAXROW(), MAXCOL() )
  764.  
  765.    IF AT( "D", SUBSTR( aFileList[ nFileItem ], 43, 6 ) ) <> 0
  766.       // Looks like a directory, let's load it...
  767.       DO CASE
  768.       CASE SUBSTR( aFileList[ nFileItem ], 1, 3 ) == ".  "
  769.          // That's the current directory!
  770.          GetNewPath( aFileMan[ FM_PATH ] )
  771.       CASE SUBSTR( aFileList[ nFileItem ], 1, 3 ) == ".. "
  772.          GetNewPath( UpPath( aFileMan[ FM_PATH ]))
  773.  
  774.       OTHERWISE
  775.          GetNewPath( SUBSTR( aFileMan[ FM_PATH ], 1, ;
  776.             RAT( "\", aFileMan[ FM_PATH ])) + ;
  777.             TRIM(SUBSTR(aFileList[nFileItem],1,12)) + "\*.*")
  778.       ENDCASE
  779.       lReloadDir := .T.
  780.    ELSE
  781.       // Must be a file.  Let's load the proper viewer and take a look
  782.       cExtension := GetFileExtension( SUBSTR(aFileList[nFileItem],1,12) )
  783.  
  784.       DO CASE
  785.       CASE cExtension == "DBF"
  786.          DBFViewer( aFileMan[ FM_RETURNFILE ] )
  787.  
  788.       OTHERWISE
  789.          GenericViewer( aFileMan[ FM_RETURNFILE ] )
  790.  
  791.       ENDCASE
  792.  
  793.       // Restore the screen
  794.       RESTSCREEN( 0, 0, MAXROW(), MAXCOL(), cOldScreen )
  795.  
  796.    ENDIF
  797.    RETURN NIL
  798.  
  799. /***
  800. *  CopyFile() --> NIL
  801. *
  802. *
  803. */
  804. STATIC FUNCTION CopyFile
  805.    LOCAL cNewName := "", cOldName := "", lKeepGoing := .F., cNewFile := ""
  806.    LOCAL nCurrent := 0, cCurrentFile := "", nCount := 0
  807.    LOCAL cOldScreen := SAVESCREEN( aFileMan[ FM_ROWTOP ] + 3,;
  808.                                    aFileMan[ FM_COLTOP ] + 2,;
  809.                                    aFileMan[ FM_ROWTOP ] + 6,;
  810.                                    aFileMan[ FM_COLTOP ] + 51 )
  811.    
  812.    IF AT( "<dir>", aFileList[ nFileItem ] ) = 0
  813.  
  814.       TONE( 800, 1 )
  815.  
  816.       IF nTagged > 0
  817.          IF YesOrNo( "Copy marked files? (Y/N)", "N" )
  818.             lKeepGoing := .T.
  819.          ENDIF
  820.       ELSE
  821.          @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLTOP ] + 1 SAY;
  822.            CHR( 16 )
  823.          @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLBOTTOM ] - 3 SAY;
  824.            CHR( 17 )
  825.          IF YesOrNo( "Copy this file? (Y/N)", "N" )
  826.             lKeepGoing := .T.
  827.          ENDIF
  828.       ENDIF
  829.  
  830.       ClearMessage()
  831.  
  832.       // Draw the box
  833.       @ aFileMan[ FM_ROWTOP ] + 3, aFileMan[ FM_COLTOP ] + 2, ;
  834.         aFileMan[ FM_ROWTOP ] + 6, aFileMan[ FM_COLTOP ] + 51 BOX;
  835.         FM_DOUBLEFRAME
  836.       @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 3 CLEAR TO ;
  837.         aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 50
  838.  
  839.       cNewName := cOldName := PADR( SUBSTR( aFileMan[ FM_PATH ], 1, ;
  840.                               RAT( "\", aFileMan[ FM_PATH ] ) ) + ;
  841.                               TRIM( SUBSTR( aFileList[ nFileItem ], 1, 12 ) ),;
  842.                               45 )
  843.  
  844.       IF lKeepGoing
  845.  
  846.          IF nTagged > 0
  847.  
  848.             cNewName := PADR( SUBSTR( aFileMan[ FM_PATH ], 1, RAT( "\", ;
  849.                                 aFileMan[ FM_PATH ] ) ), 45 )
  850.             @ aFileMan[ FM_ROWTOP ]+4, aFileMan[ FM_COLTOP ]+4 SAY;
  851.               "Copy marked files to..."
  852.             @ aFileMan[ FM_ROWTOP ]+5, aFileMan[ FM_COLTOP ]+4 GET;
  853.               cNewName PICTURE "@!@S46@K"
  854.             READ
  855.             IF LASTKEY() <> K_ESC
  856.                cNewName := TRIM( cNewName )
  857.                IF RIGHT( cNewName, 1 ) <> "\"
  858.                   cNewName += "\"
  859.                ENDIF
  860.                FOR nCurrent := 1 TO LEN( aFileList )
  861.                   IF SUBSTR( aFileList[ nCurrent ], 14, 1 ) == FM_CHECK
  862.                      cCurrentFile := SUBSTR( aFileMan[ FM_PATH ], 1, ;
  863.                                      RAT( "\", aFileMan[ FM_PATH ])) + ;
  864.                                      TRIM( SUBSTR( aFileList[ nCurrent ], 1, 12))
  865.                      cNewFile := cNewName + ;
  866.                                  TRIM( SUBSTR( aFileList[ nCurrent ], 1, 12))
  867.                      Message( "Copying " + TRIM( cCurrentFile ) )
  868.                      COPY FILE ( cCurrentFile ) TO ( cNewFile )
  869.                      aFileList[ nCurrent ] := STUFF( aFileList[ nCurrent ], ;
  870.                                               14, 1, " " )
  871.                      nTagged--
  872.                      nCount++
  873.                      IF INKEY() = K_ESC
  874.                         EXIT
  875.                      ENDIF
  876.                   ENDIF
  877.                NEXT
  878.                @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 3 CLEAR TO ;
  879.                  aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 50
  880.                @ aFileMan[ FM_ROWTOP ]+4, aFileMan[ FM_COLTOP ]+4 SAY;
  881.                  LTRIM(STR( nCount )) + IF( nCount > 1, " files copied.  ", ;
  882.                                         " file copied.  " ) + "Press any key..."
  883.                INKEY(0)
  884.             ENDIF
  885.          ELSE
  886.             @ aFileMan[ FM_ROWTOP ]+4, aFileMan[ FM_COLTOP ]+4 SAY;
  887.               "Copy current file to..."
  888.             @ aFileMan[ FM_ROWTOP ]+5, aFileMan[ FM_COLTOP ]+4 GET;
  889.               cNewName PICTURE "@!@S46@K"
  890.             READ
  891.             IF LASTKEY() <> K_ESC
  892.                IF RIGHT( cNewName, 1 ) == "\"
  893.                   cNewName += TRIM( SUBSTR( cOldName, RAT( "\", cOldName) ;
  894.                               + 1, 12 ))
  895.                ENDIF
  896.                COPY FILE ( cOldName ) TO ( cNewName )
  897.                @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 3 CLEAR TO ;
  898.                  aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 50
  899.                @ aFileMan[ FM_ROWTOP ]+4, aFileMan[ FM_COLTOP ]+4 SAY;
  900.                  "1 file copied.  Press any key..."
  901.                INKEY(0)
  902.             ENDIF
  903.  
  904.          ENDIF
  905.  
  906.          lReloadDir := .T.
  907.       ENDIF
  908.    ENDIF
  909.  
  910.  
  911.    RESTSCREEN( aFileMan[ FM_ROWTOP ] + 3, ;
  912.                aFileMan[ FM_COLTOP ] + 2, ;
  913.                aFileMan[ FM_ROWTOP ] + 6, ;
  914.                aFileMan[ FM_COLTOP ] + 51,;
  915.                cOldScreen )
  916.  
  917.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLTOP ] + 1 SAY;
  918.      CHR( 32 )
  919.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLBOTTOM ] - 3 SAY;
  920.      CHR( 32 )
  921.  
  922.    RETURN NIL
  923.  
  924. /***
  925. *  RenameFile() --> NIL
  926. *
  927. *
  928. */
  929. STATIC FUNCTION RenameFile
  930.    LOCAL cNewName := "", cOldName := ""
  931.    LOCAL cOldScreen := SAVESCREEN( aFileMan[ FM_ROWTOP ] + 3,;
  932.                                    aFileMan[ FM_COLTOP ] + 2,;
  933.                                    aFileMan[ FM_ROWTOP ] + 6,;
  934.                                    aFileMan[ FM_COLTOP ] + 51 )
  935.  
  936.    IF AT( "<dir>", aFileList[ nFileItem ] ) = 0
  937.  
  938.       // Draw the box
  939.       @ aFileMan[ FM_ROWTOP ] + 3, aFileMan[ FM_COLTOP ] + 2, ;
  940.         aFileMan[ FM_ROWTOP ] + 6, aFileMan[ FM_COLTOP ] + 51 BOX;
  941.         FM_DOUBLEFRAME
  942.       @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 3 CLEAR TO ;
  943.         aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 50
  944.  
  945.       cNewName := cOldName := PADR( SUBSTR( aFileMan[ FM_PATH ], 1, ;
  946.                               RAT( "\", aFileMan[ FM_PATH ] ) ) + ;
  947.                               TRIM( SUBSTR( aFileList[ nFileItem ], 1, 12 ) ),;
  948.                               45 )
  949.  
  950.       TONE( 800, 1 )
  951.  
  952.       @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 4 SAY "Rename " +;
  953.         SUBSTR( cNewName, 1, 38 )
  954.       @ aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 4 SAY "To" GET;
  955.         cNewName PICTURE "@!@S43@K"
  956.       READ
  957.  
  958.       IF LASTKEY() <> K_ESC
  959.          IF FILE( cNewName )
  960.             ErrorBeep()
  961.             @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 3 CLEAR TO ;
  962.               aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 50
  963.             @ aFileMan[ FM_ROWTOP ] + 4, aFileMan[ FM_COLTOP ] + 4 SAY ;
  964.               "ERROR: That file already exists!"
  965.             @ aFileMan[ FM_ROWTOP ] + 5, aFileMan[ FM_COLTOP ] + 4 SAY ;
  966.                "Press any key..."
  967.             INKEY( 0 )
  968.          ELSE
  969.             lReloadDir := .T.
  970.             RENAME ( TRIM( cOldName ) ) TO ( TRIM( cNewName ) )
  971.          ENDIF
  972.       ENDIF
  973.  
  974.    ENDIF
  975.  
  976.    RESTSCREEN( aFileMan[ FM_ROWTOP ] + 3, ;
  977.                aFileMan[ FM_COLTOP ] + 2, ;
  978.                aFileMan[ FM_ROWTOP ] + 6, ;
  979.                aFileMan[ FM_COLTOP ] + 51,;
  980.                cOldScreen )
  981.  
  982.    RETURN NIL
  983.  
  984. /***
  985. *  DeleteFile() --> NIL
  986. *
  987. *
  988. */
  989. STATIC FUNCTION DeleteFile
  990.  
  991.    LOCAL nCurrentFile := 0, cFile := ""
  992.  
  993.    TONE( 800, 1 )
  994.    IF nTagged > 0
  995.       IF YesOrNo( "Delete marked files? (Y/N)", "N" )
  996.          lReloadDir := .T.
  997.          FOR nCurrentFile := 1 TO LEN( aFileList )
  998.             cFile := SUBSTR( aFileMan[ FM_PATH ], 1, ;
  999.                      RAT( "\", aFileMan[ FM_PATH ] ) ) + ;
  1000.                      TRIM( SUBSTR( aFileList[ nCurrentFile ], 1, 12 ) )
  1001.             IF SUBSTR( aFileList[ nCurrentFile ], 14, 1 ) == FM_CHECK
  1002.                ERASE ( cFile )
  1003.                Message( "Deleting " + TRIM( cFile ) )
  1004.             ENDIF
  1005.          NEXT
  1006.          Message( LTRIM( STR( nTagged ) ) + " file(s) deleted.  Press any key..." )
  1007.          INKEY( 300 )
  1008.          nTagged := 0
  1009.       ENDIF
  1010.    ELSE
  1011.       IF AT( "<dir>", aFileList[ nFileItem ] ) = 0
  1012.          cFile := SUBSTR( aFileMan[ FM_PATH ], 1, ;
  1013.                   RAT( "\", aFileMan[ FM_PATH ] ) ) + ;
  1014.                   TRIM( SUBSTR( aFileList[ nFileItem ], 1, 12 ) )
  1015.          @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLTOP ] + 1 SAY;
  1016.            CHR( 16 )
  1017.          @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLBOTTOM ] - 3 SAY;
  1018.            CHR( 17 )
  1019.          IF YesOrNo( "Delete this file? (Y/N)", "N" )
  1020.             ERASE ( cFile )
  1021.             lReloadDir := .T.
  1022.          ENDIF
  1023.       ENDIF
  1024.    ENDIF
  1025.  
  1026.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLTOP ] + 1 SAY;
  1027.      CHR( 32 )
  1028.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLBOTTOM ] - 3 SAY;
  1029.      CHR( 32 )
  1030.  
  1031.    Message( aFileMan[ FM_PATH ] )
  1032.  
  1033.    RETURN NIL
  1034.  
  1035. /***
  1036. *  PrintFile() --> NIL
  1037. *
  1038. *
  1039. */
  1040. STATIC FUNCTION PrintFile
  1041.    LOCAL cFile := SUBSTR( aFileMan[ FM_PATH ], 1, ;
  1042.                   RAT( "\", aFileMan[ FM_PATH ] ) ) + ;
  1043.                   TRIM( SUBSTR( aFileList[ nFileItem ], 1, 12 ) )
  1044.  
  1045.    TONE( 800, 1 )
  1046.  
  1047.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLTOP ] + 1 SAY;
  1048.      CHR( 16 )
  1049.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLBOTTOM ] - 3 SAY;
  1050.      CHR( 17 )
  1051.  
  1052.    IF YesOrNo( "Print this file?", "N" )
  1053.  
  1054.       IF ISPRINTER()
  1055.          Message( "Printing " + TRIM( cFile ) )
  1056.          COPY FILE ( cFile ) TO PRN
  1057.          EJECT
  1058.       ELSE
  1059.          ErrorBeep()
  1060.          Message( "ERROR: Printer not responding!" )
  1061.          INKEY( 20 )
  1062.       ENDIF
  1063.  
  1064.    ENDIF
  1065.  
  1066.    ClearMessage()
  1067.  
  1068.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLTOP ] + 1 SAY;
  1069.      CHR( 32 )
  1070.    @ aFileMan[ FM_ROWTOP ] + 3 + nRel, aFileMan[ FM_COLBOTTOM ] - 3 SAY;
  1071.      CHR( 32 )
  1072.  
  1073.    Message( aFileMan[ FM_PATH ] )
  1074.  
  1075.    RETURN NIL
  1076.  
  1077. /***
  1078. *  DBFViewer( <cDatabase> ) --> cDatabase
  1079. *  View the contents of a database file in a window
  1080. *
  1081. */
  1082. STATIC FUNCTION DBFViewer( cDatabase )
  1083.    LOCAL cRecords := ""
  1084.  
  1085.    USE (cDatabase) ALIAS LookFile SHARED NEW READONLY
  1086.  
  1087.    IF !NETERR()
  1088.  
  1089.       @ 0, 0, MAXROW(), MAXCOL() BOX FM_DOUBLEFRAME
  1090.       cRecords := "Number of records: " + LTRIM( STR( RECCOUNT() ) )
  1091.       @ 0, MAXCOL() - 2 SAY "]"
  1092.       @ 0, (MAXCOL()-2)-LEN( cRecords )-3 SAY "[" + SPACE( LEN( cRecords ) + 2 )
  1093.       @ 0, (MAXCOL()-2)-LEN( cRecords )-1 SAY cRecords
  1094.       @ 0, 1 SAY "[ " + TRIM(cDatabase) + " ]"
  1095.       @ MAXROW(),  INT((MAXCOL()-48)/2) SAY ;
  1096.       "[ Use " + CHR(27) + CHR(18) + CHR(26)+" to move through data.  (Esc to Exit) ]"
  1097.  
  1098.       DBEDIT( 1, 1, MAXROW()-1, MAXCOL()-1 )
  1099.  
  1100.       // Close the file and select the old work area
  1101.       USE
  1102.       SELECT ( aFileMan[ FM_OLDSELECT ] )
  1103.  
  1104.    ENDIF
  1105.  
  1106.    RETURN (cDatabase)
  1107.  
  1108. /***
  1109. *  GenericViewer( <cFile> ) --> cFile
  1110. *  View the contents of a text file (?)
  1111. *
  1112. */
  1113. #define GV_BLOCKSIZE    50000
  1114.  
  1115. STATIC FUNCTION GenericViewer( cFile )
  1116.  
  1117.    LOCAL cBuffer := "", nHandle := 0, nBytes := 0
  1118.  
  1119.    cBuffer := SPACE( GV_BLOCKSIZE )
  1120.    nHandle := FOPEN( cFile )
  1121.  
  1122.    IF FERROR() != 0
  1123.       cBuffer := "Error reading file!"
  1124.    ELSE
  1125.       nBytes = FREAD( nHandle, @cBuffer, GV_BLOCKSIZE )
  1126.    ENDIF
  1127.    FCLOSE( nHandle )
  1128.  
  1129.    cBuffer := RTRIM( cBuffer )
  1130.  
  1131.    @ 0, 0 CLEAR TO MAXROW(), MAXCOL()
  1132.    @ 0, 0, MAXROW(), MAXCOL() BOX FM_DOUBLEFRAME
  1133.    @ 0, 1 SAY "[ " + TRIM(cFile) + " ]"
  1134.    @ MAXROW(),  INT((MAXCOL()-48)/2) SAY ;
  1135.    "[ Use "+CHR(27)+CHR(18)+CHR(26)+" to move through data.  (Esc to Exit) ]"
  1136.    MEMOEDIT( cBuffer, 1, 2, MAXROW() - 1, MAXCOL() - 1, .F., "MemoUDF" , 300 )
  1137.  
  1138.    RETURN( cFile )
  1139.  
  1140. #undef GV_BLOCKSIZE
  1141.  
  1142. /***
  1143. *  MemoUDF( <nMode>, <nLine>, <nColumn> ) --> 
  1144. *  
  1145. *
  1146. */
  1147. FUNCTION MemoUDF( nMode, nLine, nColumn )
  1148.    RETURN( ME_DEFAULT )
  1149.  
  1150. /***
  1151. *  TagAllFiles() --> NIL
  1152. *  Tag all files in the current directory
  1153. *
  1154. */
  1155. STATIC FUNCTION TagAllFiles
  1156.    
  1157.    LOCAL nCurrent
  1158.    nTagged := 0
  1159.    
  1160.    FOR nCurrent := 1 TO LEN( aFileList )
  1161.       IF AT( "D", SUBSTR( aFileList[ nCurrent ], 43, 6 ) ) == 0
  1162.          aFileList[ nCurrent ] := STUFF( aFileList[ nCurrent ], ;
  1163.                                          14, 1, FM_CHECK )
  1164.          nTagged++
  1165.       ENDIF
  1166.    NEXT
  1167.    
  1168.    RETURN NIL
  1169.  
  1170. /***
  1171. *  UnTagAllFiles() --> NIL
  1172. *  Untag all tagged files in the current directory
  1173. *
  1174. */
  1175. STATIC FUNCTION UnTagAllFiles
  1176.  
  1177.    LOCAL nCurrent
  1178.    nTagged := 0
  1179.  
  1180.    FOR nCurrent := 1 TO LEN( aFileList )
  1181.       aFileList[ nCurrent ] := STUFF( aFileList[ nCurrent ], 14, 1, " " )
  1182.    NEXT
  1183.  
  1184.    RETURN NIL
  1185.  
  1186.