/*
 * $Id$
 */

/*
 * The following parts are Copyright of the individual authors.
 * www - http://www.harbour-project.org
 *
 * Copyright 1999 Chen Kedem <niki@actcom.co.il>
 *    Documentation for: BROWSE(), DBEDIT(), TBROWSEDB(), DBSKIPPER()
 *
 * See doc/license.txt for licensing terms.
 *
 */

/* TODO: put more comprehensive $EXAMPLES$.
         DBEDIT() is a complex function, the doc I had made cover all the
         parameters but probably not good enough for a new user that does
         not know what this function is all about and how to use it. I am
         not that good with the English language (and I did not want to
         COPY the NG text) I suggest later some one should add to this
         text. [chkedem] */

/*  $DOC$
 *  $FUNCNAME$
 *      DBEDIT()*
 *  $CATEGORY$
 *      Data input and output
 *  $ONELINER$
 *      Browse records in a table
 *  $SYNTAX$
 *      DBEDIT( [<nTop>], [<nLeft>], [<nBottom>], [<nRight>], [<acColumns>], [<xUserFunc>], [<xColumnSayPictures>], [<xColumnHeaders>], [<xHeadingSeparators>], [<xColumnSeparators>], [<xFootingSeparators>], [<xColumnFootings>] ) --> lOk
 *  $ARGUMENTS$
 *      <par><nTop> coordinate for top row display. <nTop> could range from 0 
 *      to MAXROW(), default is 0.   </par>
 *
 *      <par><nLeft> coordinate for left column display. <nLeft> could range 
 *      from 0 to MAXCOL(), default is 0.          </par>
 *
 *      <par><nBottom> coordinate for bottom row display. <nBottom> could range
 *      from 0 to MAXROW(), default is MAXROW().   </par>
 *
 *      <par><nRight> coordinate for right column display. <nRight> could range
 *      from 0 to MAXCOL(), default is MAXCOL().   </par>
 *
 *      <par><acColumns> is an array of character expressions that contain
 *      database fields names or expressions to display in each column.
 *      If not specified, the default is to display all fields from the
 *      database in the current work area.   </par>
 *
 *      <par><xUserFunc> is a name of a user defined function or a code block
 *      that would be called every time unrecognized key is been pressed or
 *      when there are no keys waiting to be processed and DBEDIT() goes
 *      into idle mode. If <xUserFunc> is a character string, it must
 *      contain root name of a valid user define function without
 *      parentheses. Both the user define function or the code block should
 *      accept two parameters: nMode, nCurrentColumn. Both should return
 *      a numeric value that correspond to one of the expected return codes
 *      (see table below for a list of nMode and return codes).   </par>
 *
 *      <par><xColumnSayPictures> is an optional picture. If <xColumnSayPictures>
 *      is a character string, all columns would used this value as a
 *      picture string. If <xColumnSayPictures> is an array, each element
 *      should be a character string that correspond to a picture string
 *      for the column with the same index. Look at the help for @...SAY
 *      to get more information about picture values.   </par>
 *
 *      <par><xColumnHeaders> contain the header titles for each column, if this
 *      is a character string, all columns would have that same header, if
 *      this is an array, each element is a character string that contain
 *      the header title for one column. Header may be split to more than
 *      one line by placing semicolon (;) in places where you want to break
 *      line. If omitted, the default value for each column header is taken
 *      from <acColumns> or field name if <acColumns> was not specified.   </par>
 *
 *      <par><xHeadingSeparators> is an array that contain characters that draw
 *      the lines separating the headers and the fields data. Instead of an
 *      array you can use a character string that would be used to display
 *      the same line for all fields. Default value is a double line.   </par>
 *
 *      <par><xColumnSeparators> is an array that contain characters that draw
 *      the lines separating displayed columns. Instead of an array you can
 *      use a character string that would be used to display the same line
 *      for all fields. Default value is a single line.   </par>
 *
 *      <par><xFootingSeparators> is an array that contain characters that draw
 *      the lines separating the fields data area and the footing area.
 *      Instead of an array you can use a character string that would be
 *      used to display the same line for all footers. Default is to have to
 *      no footing separators.   </par>
 *
 *      <par><xColumnFootings> contain the footing to be displayed at the bottom
 *      of each column, if this is a character string, all columns would
 *      have that same footer, if this is an array, each element is a
 *      character string that contain the footer for one column. Footer may
 *      be split to more than one line by placing semicolon (;) in places
 *      where you want to break line. If omitted, no footer are displayed.   </par>
 *  $RETURNS$
 *      <par>DBEDIT() return .F. if there is no database in use or if the number
 *      of columns to display is zero, else DBEDIT() return .T.   </par>
 *  $DESCRIPTION$
 *      <par>DBEDIT() display and edit records from one or more work areas in
 *      a grid on screen. Each column is defined by element from <acColumns>
 *      and is the equivalent of one field. Each row is equivalent of one
 *      database record.   </par>

 *      <par>Following are active keys that handled by DBEDIT():      </par>
 *      <par>---------------------------------------------------      </par>
 *     <table>
 *       Left           - Move one column to the left (previous field)
 *       Right          - Move one column to the right (next field)
 *       Up             - Move up one row (previous record)
 *       Down           - Move down one row (next record)
 *       Page-Up        - Move to the previous screen
 *       Page-Down      - Move to the next screen
 *       Ctrl Page-Up   - Move to the top of the file
 *       Ctrl Page-Down - Move to the end of the file
 *       Home           - Move to the leftmost visible column
 *       End            - Move to the rightmost visible column
 *       Ctrl Left      - Pan one column to the left
 *       Ctrl Right     - Pan one column to the right
 *       Ctrl Home      - Move to the leftmost column
 *       Ctrl End       - Move to the rightmost column
 *     </table>
 *      <par>When <xUserFunc> is omitted, two more keys are active:   </par>
 *     <table>
 *       Esc            - Terminate BROWSE()
 *       Enter          - Terminate BROWSE()
 *     </table>
 *      <par>When DBEDIT() execute <xUserFunc> it pass the following arguments:
 *      nMode and the index of current record in <acColumns>. If <acColumns>
 *      is omitted, the index number is the FIELD() number of the open
 *      database structure.   </par>

 *      <par>DBEDIT() nMode could be one of the following:   </par>
 *      <par>---------------------------------------------   </par>
 *      <table>
 *       DE_IDLE        DBEDIT() is idle, all movement keys have been handled.
 *       DE_HITTOP      Attempt to cursor past top of file.
 *       DE_HITBOTTOM   Attempt to cursor past bottom of file.
 *       DE_EMPTY       No records in work area, database is empty.
 *       DE_EXCEPT      Key exception.
 *      </table>
 *      <par>The user define function or code block must return a value that tell
 *      DBEDIT() what to do next.     </par>

 *      <par>User function return codes:   </par>
 *      <par>---------------------------   </par>
 *      <table>
 *       DE_ABORT       Abort DBEDIT().
 *       DE_CONT        Continue DBEDIT() as is.
 *       DE_REFRESH     Force reread/redisplay of all data rows.
 *      </table>
 *      <par>The user function is called once in each of the following cases:   </par>
 *      <par>- The database is empty.   </par>
 *      <par>- The user try to move past top of file or past bottom file.   </par>
 *      <par>- Key exception, the uses had pressed a key that is not handled by DBEDIT().   </par>
 *      <par>- The keyboard buffer is empty or a screen refresh had just occurred   </par> 
 *      <par>DBEDIT() is a compatibility function, it is superseded by the
 *      TBrowse class and there for not recommended for new applications.   </par>
 *  $EXAMPLES$
    <fixed>
 *      // Browse a file using default values
 *      USE Test
 *      DBEDIT()
 *  </fixed>
 *  $STATUS$
 *      S
 *  $COMPLIANCE$
 *      <par><xUserFunc> can take a code block value, this is a Harbour
 *      extension.   </par>

 *      <par>CA-Clipper will throw an error if there's no database open, Harbour
 *      would return .F.   </par>

 *      <par>CA-Clipper is buggy and will throw an error if the number of columns
 *      zero, Harbour would return .F.   </par>

 *      <par>The CA-Clipper 5.2 NG state that the return value is NIL, this is
 *      wrong and should be read logical.   </par>

 *      <par>There is an undocumented result code (3) from the user defined
 *      function in Clipper (both 87 and 5.x). This is an Append Mode which:
 *      "split the screen to allow data to be appended in windowed area".
 *      This mode is not supported by Harbour.   </par>
 *  $FILES$
 *      <par>Header files are dbedit.ch, inkey.ch   </par>
 *  $SEEALSO$
 *     @...SAY,BROWSE(),TBrowse class,TRANSFORM()
 *  $END$
 */

/*  $DOC$
 *  $FUNCNAME$
 *      BROWSE()
 *  $CATEGORY$
 *      Data input and output
 *  $ONELINER$
 *      Browse a database file
 *  $SYNTAX$
 *      BROWSE( [<nTop>, <nLeft>, <nBottom>, <nRight>] ) --> lOk
 *  $ARGUMENTS$
 *      <par><nTop> coordinate for top row display.   </par>
 *
 *      <par><nLeft> coordinate for left column display.    </par>
 *
 *      <par><nBottom> coordinate for bottom row display.   </par>
 *
 *      <par><nRight> coordinate for right column display.   </par>
 *  $RETURNS$
 *      <par>BROWSE() return .F. if there is no database open in this work area,
 *      else it return .T.   </par>
 *  $DESCRIPTION$
 *      <par>BROWSE() is a general purpose database browser, without any
 *      thinking you can browse a file using the following keys:   </par>
 *      <table>
 *       Left           - Move one column to the left (previous field)
 *       Right          - Move one column to the right (next field)
 *       Up             - Move up one row (previous record)
 *       Down           - Move down one row (next record)
 *       Page-Up        - Move to the previous screen
 *       Page-Down      - Move to the next screen
 *       Ctrl Page-Up   - Move to the top of the file
 *       Ctrl Page-Down - Move to the end of the file
 *       Home           - Move to the leftmost visible column
 *       End            - Move to the rightmost visible column
 *       Ctrl Left      - Pan one column to the left
 *       Ctrl Right     - Pan one column to the right
 *       Ctrl Home      - Move to the leftmost column
 *       Ctrl End       - Move to the rightmost column
 *       Esc            - Terminate BROWSE()
 *      </table>
 *      <par>On top of the screen you see a status line with the following
 *      indication:   </par>
        <table>
 *       Record ###/### - Current record number / Total number of records.
 *       <none>         - There are no records, the file is empty.  
 *       <new>          - You are in append mode at the bottom of file.
 *       <Deleted>      - Current record is deleted. 
 *       <bof>          - You are at the top of file. 
 *      </table>
 *      <par>You should pass whole four valid coordinate, if less than four
 *      parameters are passed to BROWSE() the coordinate are default to:
 *      1, 0, MAXROW(), MAXCOL().   </par>
 *  $EXAMPLES$
    <fixed>
 *      // this one shows you how to browse around
 *      USE Around
 *      BROWSE()
    </fixed>
 *  $STATUS$
 *      S
 *  $SEEALSO$
 *      DBEDIT()*,TBrowse class
 *  $END$
 */

/*  $DOC$
 *  $FUNCNAME$
 *      TBrowseDB()
 *  $CATEGORY$
 *      TBrowse class
 *  $ONELINER$
 *      Create a new TBrowse object to be used with database file
 *  $SYNTAX$
 *      TBrowseDB( [<nTop>], [<nLeft>], [<nBottom>], [<nRight>] ) --> oBrowse
 *  $ARGUMENTS$
 *      <par><nTop> coordinate for top row display.          </par>
 *
 *      <par><nLeft> coordinate for left column display.     </par>
 *
 *      <par><nBottom> coordinate for bottom row display.    </par>
 *
 *      <par><nRight> coordinate for right column display.   </par>
 *  $RETURNS$
 *      <par>TBrowseDB() return new TBrowse object with the specified coordinate
 *      and a default :SkipBlock, :GoTopBlock and :GoBottomBlock to browse
 *      a database file.   </par>
 *  $DESCRIPTION$
 *      <par>TBrowseDB() is a quick way to create a TBrowse object along with
 *      the minimal support needed to browse a database. Note that the
 *      returned TBrowse object contain no TBColumn objects and you need
 *      to add column for each field by your self.   </par>
 *  $EXAMPLES$
        <fixed> 
 *      for a good example, look at the source code for BROWSE() function
 *      at source/rtl/browse.prg
        </fixed> 
 *  $STATUS$
 *      S   
 *  $COMPLIANCE$
 *      <par>TBrowseDB() works exactly like CA-Clipper's TBrowseDB().   </par>
 *  $SEEALSO$
 *      BROWSE(),TBColumn class,TBrowse class,TBrowseNew()
 *  $END$
 */

/*  $DOC$
 *  $FUNCNAME$
 *      dbSkipper()
 *  $CATEGORY$
 *      Data base
 *  $ONELINER$
 *      Helper function to skip a database
 *  $SYNTAX$
 *      dbSkipper( <nRecs> ) --> nSkipped
 *  $ARGUMENTS$
 *      <par><nRecs> is the number of records to skip relative to current record.
 *      Positive number would try to move the record pointer forward, while
 *      a negative number would try to move the record pointer back <nRecs>
 *      records.   </par>
 *  $RETURNS$
 *      <par>dbSkipper() return the number of actual record skipped.   </par>
 *  $DESCRIPTION$
 *      <par>dbSkipper() is a helper function used in browse mechanism to skip
 *      a number of records while giving the caller indication about the
 *      actual records skipped.     </par>
 *  $EXAMPLES$
    <fixed>
 *      // open a file and find if we've got enough records in it
 *      USE MonthSales
 *      IF dbSkipper( 100 ) == 100
 *         ? "Good work! You can party now"
 *      ELSE
 *         ? "Too bad, you should really work harder"
 *      ENDIF
 *      CLOSE
      </fixed>
 *  $STATUS$
 *      R
 *  $COMPLIANCE$
 *      <par>dbSkipper() is an XBase++ compatibility function and does not exist
 *      as a standard CA-Clipper 5.x function.   </par>

 *      <par>This function is only visible if source/rtl/browdb.prg was compiled
 *      with the HB_COMPAT_XPP flag.   </par>
 *  $SEEALSO$
 *      DBSKIP(),SKIP
 *  $END$
 */
