home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-01-11 | 33.9 KB | 1,159 lines |
- *:*********************************************************************
- *:
- *: Procedure file: VFPXTAB.PRG
- *:
- *: System: GENXTAB
- *: Author: Microsoft Corp.
- *: Copyright (c) 1993,1994,1995 Microsoft Corp.
- *:
- *:*********************************************************************
- ***********************************************************************
- *
- * Notes: This program is intended to be called by RQBE or a program
- * generated by RQBE. On entry, a table should be open in the
- * current work area, and it should contain at most one record
- * for each cell in a cross-tabulation. This table *must* be in
- * row order, or you will receive an "unexpected end of file"
- * error when you run GENXTAB.
- *
- * The rowfld field in each record becomes the y-axis (rows) for
- * a cross-tab and the colfld field becomes the x-axis (columns)
- * The actual cross-tab results are saved to the database name
- * specified by "outfname."
- *
- * The basic strategy goes like this. Produce an empty database
- * with one field/column for each unique value of input field
- * colfld, plus one additional field for input field rowfld values.
- * This process determines the column headings in the database.
- * Next fill in the rows, but only for the first field in the output
- * database--the one that contains values for input field rowfld.
- * At this point, we have column headings "across the top"
- * and row identifiers "down the side." Finally, look up
- * the cell values for the row/column intersections and put
- * them into the output database.
- *
- * Parameters:
- *
- * Parm1 - output file/cursor name (default "xtab.dbf")
- * Parm2 - cursor only (default .F.)
- * Parm3 - close input table after (default .T.)
- * Parm4 - show thermometer (default .T.)
- * Parm5 - row field (default 1)
- * Parm6 - column field (default 2)
- * Parm7 - data field (default 3)
- * Parm8 - total rows (default .F.)
- * Parm9 - totaling options (0-sum, 1-count, 2-% of total)
- *
- * Calling example:
- *
- * oNewXtab=CREATE('genxtab','query',.T.,.T.,.T.,1,6,10,.T.,0)
- * oNewXtab.MakeXtab()
- *
- ***********************************************************************
- #DEFINE C_LOCATEDBF_LOC "Please locate the input database:"
- #DEFINE C_OUTPUT_LOC "The input and output databases must be different."
- #DEFINE C_NEED3FLDS_LOC "Crosstab input databases require at least three fields"
- #DEFINE C_EMPTYDBF_LOC "Cannot prepare crosstab on empty database"
- #DEFINE C_BADROWFLD_LOC "The crosstab row field in the input; database cannot be a memo, general or picture field."
- #DEFINE C_BADCOLFLD_LOC "The crosstab column field in the input; database cannot be a memo, general or picture field."
- #DEFINE C_BADCELLFLD_LOC "The crosstab cell field in the input; database cannot be a memo, general or picture field."
- #DEFINE C_NOCOLS_LOC "No columns found."
- #DEFINE C_XSVALUES_LOC "There are too many unique values for column field. The maximum is 254."
- #DEFINE C_ENDOUTFILE_LOC "Unexpected end of output file. The input file may be out of sequence."
- #DEFINE C_UNKNOWNFLD_LOC "Unknown field type."
- #DEFINE C_XTABTERM_LOC "Cross tabulation process halted prematurely. Do you want to continue?"
- #DEFINE C_THERM1_LOC "Generating cross-tabulation ..."
- #DEFINE SUM_FIELDS 0
- #DEFINE COUNT_FIELDS 1
- #DEFINE PERCENT_FIELDS 2
-
- LPARAMETER m.p1,m.p2,m.p3,m.p4,m.p5,m.p6,m.p7,m.p8,m.p9
- oNewXtab=CREATE("genxtab",m.p1,m.p2,m.p3,m.p4,m.p5,m.p6,m.p7,m.p8,m.p9)
- oNewXtab.MakeXtab()
-
- DEFINE CLASS genxtab AS custom
-
- * Environment settings
- xtalk_stat = ""
- xsafe_stat = ""
- xesc_stat = ""
- mfieldsto = ""
- fields = ""
- udfparms = ""
- mmacdesk = ""
- in_esc = ""
- outstem = ""
- failxtab = .F.
-
- * Paramter defaults
- outfname = "xtab.dbf"
- cursonly = .F.
- closeinput = .T.
- therm_on = .T.
- rowfld = 1
- colfld = 2
- cellfld = 3
- xfoot = .F.
- totaltype = 0
-
- * Default field names
- char_blank = "C_BLANK"
- date_blank = "D_BLANK"
- null_field = "NULL"
- sumtotalfld = "Total"
- counttotalfld = "Count"
- perctotalfld = "Percent"
-
- cCountFldType = "N"
- nCountFldLen = 4
- nCountFldDec = 0
- cPercentFldType = "N"
- nPercentFldLen = 7
- nPercentFldDec = 3
-
- * Misc thermometer stuff
- g_thermwidth = 0
- lHasModalFormOnTop = .F.
- cOldMessage = ""
-
- * Map European characters to these
- stdascii = 'ueaaaaceeeiiAaEaAooouuyouaiounN'
- badchars = 'üéâäàåçêëèïîÄÅÉæÆôöòûùÿÖÜáíóúñÑ/\,-=:;{}[]!@#$%^&*.<>()?'+;
- '+|Ç¢£¥₧ƒªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧'+;
- '╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■'+CHR(39)+" "
-
-
- *!*********************************************************************
- *!
- *! PROCEDURE INIT
- *!
- *!*********************************************************************
- PROCEDURE INIT
-
- PARAMETERS outfname, cursonly, closeinput, showtherm, rowfld, colfld, cellfld, xfoot, totaltype
-
- LOCAL cname,nParms,goodchars,i
- m.nParms = PARAMETERS()
-
- THIS.save_env()
-
- * Set parameters or use default values
-
- IF m.nParms > 0 AND TYPE("m.outfname") = "C"
- THIS.outfname = m.outfname
- ENDIF
-
- IF m.nParms > 1 AND TYPE("m.cursonly") = "L"
- THIS.cursonly = m.cursonly
- ELSE
- * Default to creating the same kind of output as we got as input.
- * If the input "database" is a cursor, make the output a cursor.
- * If the input "database" is an actual database, make the output a table.
- m.cname = THIS.justfname(DBF())
- IF ISDIGIT(LEFT(m.cname,1))
- THIS.cursonly = .T.
- ENDIF
- ENDIF
-
- IF m.nParms > 2 AND TYPE("m.closeinput") = "L"
- * Close the input database
- THIS.closeinput = m.closeinput
- ENDIF
-
- IF m.nParms > 3 AND TYPE("m.showtherm ") = "L"
- * show the thermometer
- THIS.Therm_On = m.showtherm
- ENDIF
-
- IF m.nParms > 4 AND TYPE("m.rowfld ") = "N"
- * the field position in the input database for the crosstab rows
- THIS.rowfld = m.rowfld
- ENDIF
-
- IF m.nParms > 5 AND TYPE("m.colfld") = "N"
- * the field position in the input database for the crosstab columns
- THIS.colfld = m.colfld
- ENDIF
-
- IF m.nParms > 6 AND TYPE("m.cellfld") = "N"
- * the field position in the input database for the crosstab cells
- THIS.cellfld = m.cellfld
- ENDIF
-
- IF m.nParms > 7 AND TYPE("m.xfoot") = "L"
- * Create a total field
- THIS.xfoot = m.xfoot
- ENDIF
-
- IF m.nParms > 8 AND TYPE("m.totaltype") = "N"
- * Create a total field
- THIS.totaltype = m.totaltype
- ENDIF
-
- THIS.outfname = THIS.removequotes(THIS.outfname)
- THIS.outstem = THIS.juststem(THIS.outfname)
-
- * Let's set the true bad characters which aren't allowed in fields
- * Note: this will differ based on code page
- m.goodchars=""
- FOR i = 1 TO LEN(THIS.badchars)
- IF ISALPHA(SUBSTR(THIS.badchars,m.i,1))
- m.goodchars = m.goodchars + SUBSTR(THIS.badchars,m.i,1)
- ENDIF
- ENDFOR
- THIS.badchars = CHRTRAN(THIS.badchars,m.goodchars,'')
-
- ENDPROC
-
- *!*********************************************************************
- *!
- *! PROCEDURE save_env
- *!
- *!*********************************************************************
- PROCEDURE save_env
- IF SET("TALK") = "ON"
- SET TALK OFF
- THIS.xtalk_stat = "ON"
- ELSE
- THIS.xtalk_stat = "OFF"
- ENDIF
-
- THIS.cOldMessage = SET("MESSAGE",1)
- THIS.xsafe_stat = SET("SAFETY")
- SET SAFETY OFF
- THIS.xesc_stat = SET("ESCAPE")
- SET ESCAPE ON
- THIS.mfieldsto = SET("FIELDS",1)
- THIS.fields = SET("FIELDS")
- SET FIELDS TO
- SET FIELDS OFF
- THIS.udfparms = SET("UDFPARMS")
- SET UDFPARMS TO VALUE
-
- #IF "MAC" $ UPPER(VERSION(1))
- IF _MAC
- THIS.mmacdesk = SET("MACDESKTOP")
- SET MACDESKTOP ON
- ENDIF
- #ENDIF
-
- THIS.in_esc = ON('ESCAPE')
- ENDPROC
-
- *!*********************************************************************
- *!
- *! PROCEDURE Destroy
- *!
- *!*********************************************************************
- PROCEDURE Destroy
-
- PRIVATE docancl,cTmpStr
-
- IF USED("XTABTEMP")
- USE IN xtabtemp
- ENDIF
-
- IF FILE("xtabtemp.dbf")
- DELETE FILE xtabtemp.dbf
- ENDIF
- IF EMPTY(THIS.cOldMessage)
- SET MESSAGE TO
- ELSE
- SET MESSAGE TO THIS.cOldMessage
- ENDIF
- m.cTmpStr = THIS.mfieldsto
- SET FIELDS TO &cTmpStr
- IF THIS.fields = "ON"
- SET FIELDS ON
- ELSE
- SET FIELDS OFF
- ENDIF
-
- cTmpStr=THIS.udfparms
- SET UDFPARMS TO &cTmpStr
-
- IF THIS.xsafe_stat = "ON"
- SET SAFETY ON
- ENDIF
- IF THIS.xesc_stat = "ON"
- SET ESCAPE ON
- ELSE
- SET ESCAPE OFF
- ENDIF
- IF THIS.xtalk_stat = "ON"
- SET TALK ON
- ENDIF
- #IF "MAC" $ UPPER(VERSION(1))
- IF _MAC
- m.cTmpStr = THIS.mmacdesk
- SET MACDESKTOP &cTmpStr
- ENDIF
- #ENDIF
-
- cTmpStr = THIS.in_esc
- ON ESCAPE &cTmpStr
-
- IF THIS.failxtab
- THIS.outfname = ''
- THIS.deactthermo()
- ENDIF
-
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Function: MakeXTab()
- *!
- *!*********************************************************************
- PROCEDURE MakeXTab
- * Set ON ESCAPE here
- LOCAL oThisXtab,aXtabs
- DIMENSION aXtabs[1]
- =AINSTANCE(aXtabs,'genxtab')
- oThisXtab = aXtabs[1]+".esc_proc()"
- ON ESCAPE &oThisXtab
-
- * Call main program
- THIS.RunXTab()
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Function: RunXTab()
- *!
- *!*********************************************************************
- PROCEDURE RunXTab
-
- LOCAL dbfname,dbfstem,ok,cdec,i
- LOCAL numflds,rowfldname,colfldname,cellfldname
- LOCAL totfldname,gtotal,outf1name,f1,f2,f3
- LOCAL colcnt,coluniq,outarray
- LOCAL sumallflds,RowFldType
- DIMENSION colcnt[1],coluniq[1],outarray[1]
-
- m.dbfname = ALIAS()
- m.dbfstem = THIS.Juststem(m.dbfname)
-
- * Select one, if no database is open in the current workarea
- m.ok = .F.
- DO WHILE NOT m.ok
- DO CASE
- CASE EMPTY(m.dbfname)
- m.dbfname = GETFILE('DBF',C_LOCATEDBF_LOC)
- m.dbfstem = THIS.juststem(m.dbfname)
- IF EMPTY(m.dbfname)
- * User canceled out of dialog, so quit the program
- THIS.failxtab = .T.
- RETURN
- ENDIF
- CASE FULLPATH(THIS.defaultext(m.dbfname,'DBF')) == ;
- FULLPATH(THIS.defaultext(THIS.outfname,'DBF'))
- THIS.ALERT(C_OUTPUT_LOC)
- m.dbfname = ''
- OTHERWISE
- IF USED(m.dbfstem)
- SELECT (m.dbfstem)
- ELSE
- SELECT 0
- USE (m.dbfname) ALIAS (m.dbfstem)
- ENDIF
- IF FCOUNT() < 3
- THIS.ALERT(C_NEED3FLDS_LOC)
- m.dbfname = ''
- ELSE
- ok = .T.
- ENDIF
- ENDCASE
- ENDDO
-
- IF RECCOUNT() = 0
- THIS.ALERT(C_EMPTYDBF_LOC)
- THIS.failxtab = .T.
- RETURN
- ENDIF
-
- * Gather information on the currently selected database fields
-
- DIMENSION inpfields[FCOUNT(),4]
- m.numflds = AFIELDS(inpfields)
-
- * Map the physical input database field to logical field positions
-
- m.rowfldname = inpfields[THIS.rowfld,1]
- m.colfldname = inpfields[THIS.colfld,1]
- m.cellfldname = inpfields[THIS.cellfld,1]
-
- * None of these fields are allowed to be memo fields
- IF inpfields[THIS.rowfld,2] $ 'MGP'
- THIS.ALERT(C_BADROWFLD_LOC)
- THIS.failxtab = .T.
- RETURN
- ENDIF
- IF inpfields[THIS.colfld,2] $ 'MGP'
- THIS.ALERT(C_BADCOLFLD_LOC)
- THIS.failxtab = .T.
- RETURN
- ENDIF
- IF inpfields[THIS.cellfld,2] $ 'MGP'
- THIS.ALERT(C_BADCELLFLD_LOC)
- THIS.failxtab = .T.
- RETURN
- ENDIF
-
- THIS.acttherm(C_THERM1_LOC)
- THIS.updtherm(5)
-
- * Count the number of columns we need to create the cross tab.
- * This step could be combined with the following one so that there
- * would only be one SELECT operation performed. It is coded in this
- * way to avoid running out of memory if there are an unexpectedly
- * large number of unique values of field 2 in the input database.
-
- SELECT COUNT(DISTINCT &colfldname) FROM (m.dbfname) INTO ARRAY colcnt
-
- DO CASE
- CASE colcnt[1] > 254
- THIS.ALERT(C_XSVALUES_LOC)
- THIS.failxtab = .T.
- RETURN
- CASE colcnt[1] = 0
- THIS.ALERT(C_NOCOLS_LOC)
- THIS.failxtab = .T.
- RETURN
- ENDCASE
-
- * Get the number of decimal places in numeric fields
- * and extract all the unique values of colfldname
- IF inpfields[THIS.colfld,2] $ 'NF' && numeric or floating field
- m.cdec = inpfields[THIS.colfld,4]
- * Handle numbers separately to preserve correct sort order
- SELECT DISTINCT &colfldname ;
- FROM (m.dbfname) INTO ARRAY coluniq
- FOR i = 1 TO ALEN(coluniq)
- coluniq[m.i] = THIS.mapname(coluniq[m.i],m.cdec)
- ENDFOR
- ELSE && non-numeric field
- m.cdec = 0
- * Create an array to hold the output database fields.
- SELECT DISTINCT EVAL("THIS.mapname(&colfldname,m.cdec)") FROM (m.dbfname) INTO ARRAY coluniq
- ENDIF
-
- THIS.updtherm(15)
-
- * The field type, length and decimals in the output array control the
- * cross-tab cells
- IF !THIS.xfoot
- DIMENSION outarray[ALEN(coluniq)+1,4]
- ELSE
- DIMENSION outarray[ALEN(coluniq)+2,4]
- ENDIF
-
- * Field 1 in the output DBF holds the unique values of the row input field.
- * It is handled separately from the other fields, which take their names
- * from input database colfld and their parameters (e.g., length) from
- * input database cellfld.
-
- outarray[1,1] = THIS.mapname(inpfields[THIS.rowfld,1])
- outarray[1,2] = inpfields[THIS.rowfld,2] && field type
- outarray[1,3] = inpfields[THIS.rowfld,3] && field length
- outarray[1,4] = inpfields[THIS.rowfld,4] && decimals
-
- m.RowFldType = outarray[1,2]
-
- FOR i = 2 TO ALEN(coluniq) + 1
- outarray[m.i,1] = THIS.mapname(coluniq[m.i-1],m.cdec)
- outarray[m.i,2] = inpfields[THIS.cellfld,2] && field type
- outarray[m.i,3] = inpfields[THIS.cellfld,3] && field length
- outarray[m.i,4] = inpfields[THIS.cellfld,4] && decimals
- ENDFOR
-
- * Create a field for the cross-footing, if that option was selected
- * By default, make sure we have a numeric field here
-
- * Check type of data field, and use count if not numeric.
- IF ATC(inpfields[THIS.cellfld,2],"NFYB") = 0
- THIS.totaltype = COUNT_FIELDS
- ENDIF
-
- IF THIS.xfoot
- DO CASE
- CASE THIS.totaltype = COUNT_FIELDS
- * Since Max columns is 256, assume N (4)
- outarray[ALEN(coluniq)+2,1] = THIS.counttotalfld
- outarray[ALEN(coluniq)+2,2] = THIS.cCountFldType && field type
- outarray[ALEN(coluniq)+2,3] = THIS.nCountFldLen && field length
- outarray[ALEN(coluniq)+2,4] = THIS.nCountFldDec && field length
- CASE THIS.totaltype = PERCENT_FIELDS
- * Percent of total, use three decimals
- outarray[ALEN(coluniq)+2,1] = THIS.perctotalfld
- outarray[ALEN(coluniq)+2,2] = THIS.cPercentFldType && field type
- outarray[ALEN(coluniq)+2,3] = THIS.nPercentFldLen && field length
- outarray[ALEN(coluniq)+2,4] = THIS.nPercentFldDec && decimals
- OTHERWISE
- outarray[ALEN(coluniq)+2,1] = THIS.sumtotalfld
- outarray[ALEN(coluniq)+2,2] = inpfields[THIS.cellfld,2] && field type
- outarray[ALEN(coluniq)+2,4] = inpfields[THIS.cellfld,4] && decimals
- IF ATC(inpfields[THIS.cellfld,2],"YB")#0
- outarray[ALEN(coluniq)+2,3] = inpfields[THIS.cellfld,3] && field length
- ELSE
- * Add a little extra space for calculations
- outarray[ALEN(coluniq)+2,3] = MIN(inpfields[THIS.cellfld,3]+2,20) && field length
- ENDIF
- ENDCASE
- ENDIF
-
- * Make sure that the output file is not already in use somewhere
- IF USED(THIS.outstem)
- SELECT (THIS.outstem)
- USE
- ENDIF
-
-
- IF !THIS.cursonly
- CREATE TABLE (THIS.outfname) FROM ARRAY outarray
- ELSE
- CREATE CURSOR (THIS.outstem) FROM ARRAY outarray
- ENDIF
-
- THIS.updtherm(25)
-
- * Get rid of the temporary arrays
- RELEASE outarray, coluniq, inpfields
-
- * -------------------------------------------------------------------------
- * Add output database rows and replace the first field
- * -------------------------------------------------------------------------
-
- * Select distinct rows into a table (instead of an array) so that
- * there can be lots of rows. If we select into an array, we may
- * run out of RAM if there are many rows.
-
- SELECT DISTINCT &rowfldname FROM (m.dbfname) INTO TABLE xtabtemp
- THIS.updtherm(30)
-
- SELECT (THIS.outstem)
- GO TOP
- APPEND FROM xtabtemp FIELD (FIELD(1))
-
- THIS.updtherm(35)
-
- * -------------------------------------------------------------------------
- * Look up and replace the cell values
- * -------------------------------------------------------------------------
- *
- * This algorithm makes one pass through the input file, dropping its
- * values into the output file. It exploits the fact that the output
- * file is known to be in row order.
- *
-
- * Start at the top of the output file
- SELECT (THIS.outstem)
- GOTO TOP
- outf1name = FIELD(1)
-
- * Start at the top of the input file
- SELECT (m.dbfstem)
- GOTO TOP
-
- SCAN
- m.f1 = EVAL(m.rowfldname) && get next row value from input
- m.f2 = THIS.mapname(EVAL(m.colfldname),m.cdec) && get corresponding column value
- m.f3 = EVAL(m.cellfldname) && get cell value
-
- * Find the right row in the output file
- SELECT (THIS.outstem)
- DO WHILE !(EVAL(outf1name) == m.f1) AND !EOF()
- SKIP
- ENDDO
-
- IF !EOF()
- IF TYPE(m.f2) $ "NFYB"
- REPLACE (m.f2) WITH &f2 + m.f3
- ELSE
- REPLACE (m.f2) WITH m.f3
- ENDIF
- ELSE
- THIS.ALERT(C_ENDOUTFILE_LOC)
- THIS.failxtab = .T.
- RETURN
- ENDIF
-
- SELECT (m.dbfstem)
-
- * Map thermometer to remaining portion of display
- DO CASE
- CASE RECCOUNT() > 1000
- IF RECNO() % 100 = 0
- THIS.updtherm(INT(RECNO() / RECCOUNT() * 65)+ 35)
- ENDIF
- OTHERWISE
- IF RECNO() % 10 = 0
- THIS.updtherm(INT(RECNO() / RECCOUNT() * 65)+ 35)
- ENDIF
- ENDCASE
- ENDSCAN
-
-
- * Cross-foot the columns and put the results into the total field
- IF THIS.xfoot
- SELECT (THIS.outstem)
- m.totfldname = FIELD(FCOUNT())
- IF THIS.totaltype = PERCENT_FIELDS
- * Need to get total here
- PRIVATE aSums,nFirstField
- m.nFirstField = IIF(ATC(m.RowFldType,"NFYB")=0,1,2)
- SUM ALL TO ARRAY aSums
- m.sumallflds = 0
- FOR i = m.nFirstField TO (ALEN(aSums)-1) &&skip last field which has totals
- m.sumallflds = m.sumallflds + aSums[m.i]
- ENDFOR
- ENDIF
- SCAN
- * Sum the relevant fields
- m.gtotal = 0
- FOR i = 2 TO FCOUNT() - 1
- DO CASE
- CASE THIS.totaltype = COUNT_FIELDS
- m.gtotal = m.gtotal + IIF( EMPTY(EVAL(FIELD(m.i))) OR ISNULL(EVAL(FIELD(m.i))),0,1)
- OTHERWISE
- m.gtotal = m.gtotal + EVAL(FIELD(m.i))
- ENDCASE
- ENDFOR
- IF THIS.totaltype = PERCENT_FIELDS
- m.gtotal = IIF(m.sumallflds=0 OR m.gtotal=0,0,ROUND(m.gtotal/m.sumallflds*100,THIS.nPercentFldDec))
- ENDIF
- REPLACE (m.totfldname) WITH m.gtotal
- ENDSCAN
- ENDIF
-
- THIS.updtherm(100)
- THIS.deactthermo()
-
- IF USED("XTABTEMP")
- USE IN xtabtemp
- ENDIF
-
- IF FILE("xtabtemp.dbf")
- DELETE FILE xtabtemp.dbf
- ENDIF
-
- * Close the input database
- IF THIS.closeinput
- SELECT (m.dbfstem)
- USE
- ENDIF
-
- * Leave the output database/cursor selected
- SELECT (THIS.outstem)
- GOTO TOP
-
- * Do closing housekeeping
- RETURN
- ENDPROC
-
-
- *!*********************************************************************
- *!
- *! Function: MAPNAME()
- *!
- *!*********************************************************************
- FUNCTION mapname
- * Translate a field value of any type into a string containing a valid
- * field name.
-
- PARAMETER in_name, in_dec
- LOCAL retval
-
- IF PARAMETERS() = 1
- m.in_dec = 0
- ENDIF
- DO CASE
- CASE ISNULL(m.in_name)
- m.retval = THIS.null_field
- CASE TYPE("m.in_name") $ 'CM'
- DO CASE
- CASE EMPTY(m.in_name)
- m.retval = THIS.char_blank
- OTHERWISE
- * We need to replace bad characters here with "_"
- m.retval = SUBSTR(CHRTRAN(m.in_name,THIS.badchars,REPLICATE("_",LEN(THIS.badchars)-1)),1,10)
- IF !ISALPHA(LEFT(m.retval,1))
- m.retval = 'C_'+LEFT(m.retval,8)
- ENDIF
- ENDCASE
- CASE TYPE("m.in_name") $ 'NFYB'
- m.retval = 'N_'+ALLTRIM(CHRTRAN(STR(m.in_name,8,in_dec),'.',''))
- CASE TYPE("m.in_name") $ 'DT'
- DO CASE
- CASE EMPTY(m.in_name)
- m.retval = THIS.date_blank
- OTHERWISE
- m.retval = 'D_' + CHRTRAN(DTOS(m.in_name),THIS.badchars,REPLICATE("_",LEN(THIS.badchars)-1))
- ENDCASE
- CASE TYPE("m.in_name") = 'L'
- IF m.in_name = .T.
- m.retval = 'T'
- ELSE
- m.retval = 'F'
- ENDIF
- OTHERWISE
- * Should never happen
- THIS.alert(C_UNKNOWNFLD_LOC)
- RETURN ""
- ENDCASE
-
- RETURN PADR(UPPER(ALLTRIM(m.retval)),10)
-
- ENDFUNC
-
-
- *!*********************************************************************
- *!
- *! Procedure: ERROR
- *!
- *!*********************************************************************
- PROCEDURE ERROR
- PARAMETERS nError, cMethod, nLine
-
- THIS.alert('Line : '+ALLTRIM(STR(m.nLine))+CHR(13) ;
- +'Program: '+m.cMethod+CHR(13) ;
- +'Error: '+ALLT(STR(nError))+CHR(13) ;
- +'Message: '+MESSAGE()+CHR(13);
- +'Code: '+MESSAGE(1))
- THIS.failxtab = .T.
- RETURN TO MakeXtab
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: ALERT
- *!
- *!*********************************************************************
- PROCEDURE alert
- LPARAMETERS strg
- =MESSAGEBOX(m.strg)
- RETURN
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: ESC_PROC
- *!
- *!*********************************************************************
- PROCEDURE esc_proc
- CLEAR TYPEAHEAD
- IF MESSAGEBOX(C_XTABTERM_LOC,36) = 6
- RETURN
- ELSE
- THIS.failxtab = .T.
- RETURN TO MakeXtab
- ENDIF
- ENDPROC
-
- *!*****************************************************************************
- *!
- *! Procedure: PARTIALFNAME
- *!
- *!*****************************************************************************
- FUNCTION partialfname
- PARAMETER m.filname, m.fillen
- * Return a filname no longer than m.fillen characters. Take some chars
- * out of the middle if necessary. No matter what m.fillen is, this function
- * always returns at least the file stem and extension.
- PRIVATE m.bname, m.elipse
- m.elipse = "..." + c_pathsep
- m.bname = THIS.justfname(m.filname)
- DO CASE
- CASE LEN(m.filname) <= m.fillen
- RETURN filname
- CASE LEN(m.bname) + LEN(m.elipse) >= m.fillen
- RETURN m.bname
- OTHERWISE
- m.remain = MAX(m.fillen - LEN(m.bname) - LEN(m.elipse), 0)
- RETURN LEFT(THIS.justpath(m.filname),remain)+m.elipse+m.bname
- ENDCASE
- ENDFUNC
-
- *!*****************************************************************************
- *!
- *! Procedure: removequotes
- *!
- *!*****************************************************************************
- FUNCTION removequotes
- PARAMETER m.fname
- PRIVATE m.leftchar, m.rightchar
- m.fname = ALLTRIM(m.fname)
- m.leftchar = LEFT(m.fname,1)
- m.rightchar = RIGHT(m.fname, 1)
-
- IF m.leftchar = '"' AND m.rightchar = '"' ;
- OR m.leftchar = "'" AND m.rightchar = "'" ;
- OR m.leftchar = '[' AND m.rightchar = ']'
- RETURN SUBSTR(m.fname, 2, LEN(m.fname) - 2)
- ELSE
- RETURN m.fname
- ENDIF
- ENDFUNC
-
- *!*********************************************************************
- *!
- *! Function: JUSTSTEM()
- *!
- *!*********************************************************************
- FUNCTION juststem
- * Return just the stem name from "filname"
- PARAMETERS filname
- PRIVATE ALL
- IF RAT('\',m.filname) > 0
- m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
- ENDIF
- IF RAT(':',m.filname) > 0
- m.filname = SUBSTR(m.filname,RAT(':',m.filname)+1,255)
- ENDIF
- IF RAT('.',m.filname) > 0
- m.filname = SUBSTR(m.filname,1,RAT('.',m.filname)-1)
- ENDIF
- RETURN ALLTRIM(UPPER(m.filname))
- ENDFUNC
-
- *!*********************************************************************
- *!
- *! Procedure: FORCEEXT
- *!
- *!*********************************************************************
- FUNCTION forceext
- * Force the extension of "filname" to be whatever ext is.
- PARAMETERS filname,ext
- PRIVATE ALL
- IF SUBSTR(m.ext,1,1) = "."
- m.ext = SUBSTR(m.ext,2,3)
- ENDIF
-
- m.pname = THIS.justpath(m.filname)
- m.filname = THIS.justfname(UPPER(ALLTRIM(m.filname)))
- IF RAT('.',m.filname) > 0
- m.filname = SUBSTR(m.filname,1,RAT('.',m.filname)-1) + '.' + m.ext
- ELSE
- m.filname = m.filname + '.' + m.ext
- ENDIF
- RETURN THIS.addbs(m.pname) + m.filname
- ENDFUNC
-
- *!*********************************************************************
- *!
- *! Function: DEFAULTEXT()
- *!
- *!*********************************************************************
- FUNCTION defaultext
- * Add a default extension to "filname" if it doesn't have one already
- PARAMETERS filname,ext
- PRIVATE ALL
- IF SUBSTR(ext,1,1) = "."
- m.ext = SUBSTR(m.ext,2,3)
- ENDIF
-
- m.pname = THIS.justpath(m.filname)
- m.filname = THIS.justfname(UPPER(ALLTRIM(m.filname)))
- IF !EMPTY(m.filname) AND AT('.',m.filname) = 0
- m.filname = m.filname + '.' + m.ext
- RETURN THIS.addbs(m.pname) + m.filname
- ELSE
- RETURN filname
- ENDIF
- ENDFUNC
-
- *!*********************************************************************
- *!
- *! Function: JUSTFNAME()
- *!
- *!*********************************************************************
- FUNCTION justfname
- * Return just the filename (i.e., no path) from "filname"
- PARAMETERS filname
- PRIVATE ALL
- IF RAT('\',m.filname) > 0
- m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
- ENDIF
- IF RAT(':',m.filname) > 0
- m.filname = SUBSTR(m.filname,RAT(':',m.filname)+1,255)
- ENDIF
- RETURN ALLTRIM(UPPER(m.filname))
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: JUSTPATH
- *!
- *!*********************************************************************
- FUNCTION justpath
- * Return just the path name from "filname"
- PARAMETERS m.filname
- PRIVATE ALL
- m.filname = ALLTRIM(UPPER(m.filname))
- m.pathsep = IIF(_MAC,":", "\")
- IF _MAC
- m.found_it = .F.
- m.maxchar = max(RAT("\", m.filname), RAT(":", m.filname))
- IF m.maxchar > 0
- m.filname = SUBSTR(m.filname,1,m.maxchar)
- IF RIGHT(m.filname,1) $ ":\" AND LEN(m.filname) > 1 ;
- AND !(SUBSTR(m.filname,LEN(m.filname)-1,1) $ ":\")
- m.filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
- ENDIF
- RETURN m.filname
- ENDIF
- ELSE
- IF m.pathsep $ filname
- m.filname = SUBSTR(m.filname,1,RAT(m.pathsep,m.filname))
- IF RIGHT(m.filname,1) = m.pathsep AND LEN(m.filname) > 1 ;
- AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> m.pathsep
- m.filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
- ENDIF
- RETURN m.filname
- ENDIF
- ENDIF
- RETURN ''
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: ADDBS
- *!
- *!*********************************************************************
- FUNCTION addbs
- * Add a backslash to a path name, if there isn't already one there
- PARAMETER pathname
- PRIVATE ALL
- m.pathname = ALLTRIM(UPPER(m.pathname))
- IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname)
- m.pathname = m.pathname + IIF(_MAC,":",'\')
- ENDIF
- RETURN m.pathname
- ENDPROC
-
-
- *!*********************************************************************
- *!
- *! Procedure: HasModalForm
- *!
- *!*********************************************************************
- PROCEDURE HasModalForm
- * Tests to see if a modal form is active so since it conflicts with Therm
- LOCAL i
- FOR i = 1 TO _SCREEN.FormCount
- IF _Screen.Forms[m.i].Windowtype = 1 OR ;
- (TYPE("_Screen.Forms[m.i].Parent.Windowtype")="N" AND ;
- _Screen.Forms[m.i].Parent.Windowtype = 1)
- RETURN .T.
- EXIT
- ENDIF
- ENDFOR
- RETURN .F.
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: ActTherm
- *!
- *!*********************************************************************
- PROCEDURE ActTherm
- PARAMETER prompt
- IF !THIS.therm_on
- RETURN
- ENDIF
- * Test to see if we have a modal form up which prevents Therm window from being visible.
- IF THIS.HasModalForm()
- THIS.lHasModalFormOnTop = .T.
- RETURN
- ENDIF
-
- LOCAL m.text,g_dlgface,g_dlgsize,g_dlgstyle
- m.g_dlgface = IIF(_MAC,"Geneva","MS Sans Serif")
- m.g_dlgsize = IIF(_MAC,10,8.000)
- m.g_dlgstyle = IIF(_MAC,"","B")
-
- m.text = ""
- IF _MAC OR _WINDOWS
- IF TXTWIDTH(m.prompt, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle) > 43
- DO WHILE TXTWIDTH(m.prompt+"...", m.g_dlgface, m.g_dlgsize, m.g_dlgstyle) > 43
- m.prompt = LEFT(m.prompt, LEN(m.prompt)-1)
- ENDDO
- m.prompt = m.prompt + "..."
- ENDIF
- DO CASE
- CASE _WINDOWS
- DEFINE WINDOW thermomete ;
- AT INT((SROW() - (( 5.615 * ;
- FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
- FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
- INT((SCOL() - (( 63.833 * ;
- FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
- FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
- SIZE 5.615,63.833 ;
- FONT m.g_dlgface, m.g_dlgsize ;
- STYLE m.g_dlgstyle ;
- NOFLOAT ;
- NOCLOSE ;
- NONE ;
- COLOR RGB(0, 0, 0, 192, 192, 192)
- MOVE WINDOW thermomete CENTER
- ACTIVATE WINDOW thermomete NOSHOW
-
- @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
- @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle
- @ 0.000,0.000 TO 0.000,63.833 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 0.000,0.000 TO 5.615,0.000 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 0.385,0.667 TO 5.231,0.667 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 0.308,0.667 TO 0.308,63.167 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 0.385,63.000 TO 5.308,63.000 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 5.231,0.667 TO 5.231,63.167 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 5.538,0.000 TO 5.538,63.833 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 0.000,63.667 TO 5.615,63.667 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 3.000,3.333 TO 4.231,3.333 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 3.000,60.333 TO 4.308,60.333 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 3.000,3.333 TO 3.000,60.333 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 4.231,3.333 TO 4.231,60.500 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- THIS.g_thermwidth = 56.269
- CASE _MAC
- DEFINE WINDOW thermomete ;
- AT INT((SROW() - (( 5.62 * ;
- FONTMETRIC(1, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
- FONTMETRIC(1, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2), ;
- INT((SCOL() - (( 63.83 * ;
- FONTMETRIC(6, m.g_dlgface, m.g_dlgsize, m.g_dlgstyle )) / ;
- FONTMETRIC(6, WFONT(1,""), WFONT( 2,""), WFONT(3,"")))) / 2) ;
- SIZE 5.62,63.83 ;
- FONT m.g_dlgface, m.g_dlgsize ;
- STYLE m.g_dlgstyle ;
- NOFLOAT ;
- NOCLOSE ;
- NONE ;
- COLOR RGB(0, 0, 0, 192, 192, 192)
- MOVE WINDOW thermomete CENTER
- ACTIVATE WINDOW thermomete NOSHOW
-
- IF ISCOLOR()
- @ 0.000,0.000 TO 5.62,63.83 PATTERN 1;
- COLOR RGB(192, 192, 192, 192, 192, 192)
- @ 0.000,0.000 TO 0.000,63.83 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 0.000,0.000 TO 5.62,0.000 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 0.385,0.67 TO 5.23,0.67 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 0.31,0.67 TO 0.31,63.17 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 0.385,63.000 TO 5.31,63.000 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 5.23,0.67 TO 5.23,63.17 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 5.54,0.000 TO 5.54,63.83 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 0.000,63.67 TO 5.62,63.67 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 3.000,3.33 TO 4.23,3.33 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 3.000,60.33 TO 4.31,60.33 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- @ 3.000,3.33 TO 3.000,60.33 ;
- COLOR RGB(128, 128, 128, 128, 128, 128)
- @ 4.23,3.33 TO 4.23,60.33 ;
- COLOR RGB(255, 255, 255, 255, 255, 255)
- ELSE
- @ 0.000, 0.000 TO 5.62, 63.830 PEN 2
- @ 0.230, 0.500 TO 5.39, 63.333 PEN 1
- ENDIF
- @ 0.5,3 SAY m.text FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
- COLOR RGB(0,0,0,192,192,192)
- @ 1.5,3 SAY m.prompt FONT m.g_dlgface, m.g_dlgsize STYLE m.g_dlgstyle+"T" ;
- COLOR RGB(0,0,0,192,192,192)
-
- THIS.g_thermwidth = 56.27
- IF !ISCOLOR()
- @ 3.000,3.33 TO 4.23,THIS.g_thermwidth + 3.33
- ENDIF
- ENDCASE
- SHOW WINDOW thermomete TOP
- ELSE
-
- DEFINE WINDOW thermomete;
- FROM INT((SROW()-6)/2), INT((SCOL()-57)/2) ;
- TO INT((SROW()-6)/2) + 6, INT((SCOL()-57)/2) + 57;
- DOUBLE COLOR SCHEME 5
- ACTIVATE WINDOW thermomete NOSHOW
-
- THIS.g_thermwidth = 50
- @ 0,3 SAY m.prompt
- @ 2,1 TO 4,THIS.g_thermwidth+4
-
- SHOW WINDOW thermomete TOP
- ENDIF
- RETURN
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: updtherm
- *!
- *!*********************************************************************
- PROCEDURE updtherm
- PARAMETER Percent
- IF !THIS.therm_on
- RETURN
- ENDIF
- PRIVATE m.nblocks, m.percent
- IF THIS.lHasModalFormOnTop
- SET MESSAGE TO C_THERM1_LOC+ALLTRIM(STR(percent))+"%"
- RETURN
- ENDIF
- IF !WEXIST("thermomete")
- DO acttherm WITH C_THERM1_LOC
- ENDIF
- ACTIVATE WINDOW thermomete
-
- m.nblocks = (m.percent/100) * (THIS.g_thermwidth)
- DO CASE
- CASE _WINDOWS
- @ 3.000,3.333 TO 4.231,m.nblocks + 3.333 ;
- PATTERN 1 COLOR RGB(128, 128, 128, 128, 128, 128)
- CASE _MAC
- @ 3.000,3.33 TO 4.23,m.nblocks + 3.33 ;
- PATTERN 1 COLOR RGB(0, 0, 128, 0, 0, 128)
- OTHERWISE
- @ 3,3 SAY REPLICATE("█",m.nblocks)
- ENDCASE
- RETURN
-
- ENDPROC
-
- *!*********************************************************************
- *!
- *! Procedure: deactthermo
- *!
- *!*********************************************************************
- PROCEDURE deactthermo
- IF !THIS.therm_on
- RETURN
- ENDIF
- IF THIS.lHasModalFormOnTop
- RETURN
- ENDIF
- IF WEXIST("thermomete")
- RELEASE WINDOW thermomete
- ENDIF
- RETURN
- ENDPROC
-
- ENDDEFINE