*-------------------------------------------------------------------------------------------------------------------------------------------------------- * (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!! *-------------------------------------------------------------------------------------------------------------------------------------------------------- *< FOXBIN2PRG: Version="1.21" SourceFile="vfpxworkbookxlsx.vcx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries) * * DEFINE CLASS vfpxworkbookxlsx AS label *< CLASSDATA: Baseclass="label" Timestamp="" Scale="Pixels" Uniqueid="" /> #INCLUDE "vfpxworkbookxlsx.h" * *m: addclassdefinednumericformats && Adds pre-defined numeric cell formats *m: addcustomnumericformat && Adds a new custom defined numeric format *m: addindexcolor && Adds a new indexed color definition *m: addinlinefontobject && Adds an object for setting the inline formatting of cell text *m: addmrucolor && Adds a custom defined MRU color to the workbook *m: addnamedrange && Adds a name range to the workbook *m: addnumericformat && Adds a numeric format expression to be used *m: addsheet && Adds a new sheet to the workbook *m: addstringvalue && Adds a string value to the internal cursor *m: addstyleborders && Adds to the cell style a border definition *m: addstylefill && Adds to the cell style a fill definition *m: addstylefont && Adds to the cell style a font definition *m: addstylehorizalignment && Adds to the cell style horizontal cell alignment *m: addstyleindent && Adds to the style indent definition *m: addstylenumericformat && Adds to the style definition numeric format *m: addstyletextrotation && Adds to the style definition text rotation *m: addstylevertalignment && Adds to the cell style vertical cell alignment *m: addstylewordwrap && Adds to the style definition word wrap *m: cellformatpainter && Copies the formatting of a source cell to other cells *m: cellrefasciitoindex && Converts a 'AA444' cell reference to the row and column index values *m: clearcellvalidation && Clears/deletes the named range from the workbook *m: clearcellvalue && Clears the cell value *m: columnasciitoindex && Converts Excel Ascii column value to index value *m: columnindextoascii && Gets the column ASCII code for the column index *m: convertcolortohex && Converts a color value (integer) to Hex representation *m: converthexstringtonumeric && ConvertHexStringToNumeric *m: convertpixelstoexcelunits && Converts Pixel measurement to Excel measurement *m: createexcelfile && Creates the Excel file from the components *m: createformatstyle && Creates a new format style definition *m: createinlineformattext && Creates an in-line text formatted definition *m: createworkbook && Creates a new workbook object *m: createworkbookex && Internal method for creating a workbook *m: createworkingcursors && Creates the working cursors for worksheet definitions *m: createworkingdirectories && Creates the working directories for the XML files *m: debugcursorstofile && Debugging use for saving the internal cursors to a text file *m: debugoutput && Limited functions for debugging *m: debug_assign *m: declaredll && Declares the required support Win32 API *m: deleteallworkbooks && Deletes all workbooks *m: deletesheet && Deletes the sheet from the Workbook *m: deleteworkbook && Deletes the selected workbook *m: demo && Demo for the features of this class *m: derivesheetname && Derives the sheet name *m: destroyworkingcursors && Destroys the working cursors *m: documentation && Documentation of the methods and properties for this class *m: freezepanes && Freezes the panes of the sheet *m: getalphanumericsplit && Returns the position of the alpha and numeric split *m: getbordersrecord && Gets the border record; returns True if found, or False in not found *m: getcellalignment && Returns the cell alignment *m: getcellborders && Returns the cell border info *m: getcelldatatype && Returns the data type for the selected cell *m: getcellfill && Returns the fill info for the cell *m: getcellfont && Returns the cell font settings *m: getcellformula && Returns the cell formula expression *m: getcellformulafromxml && Gets the cell formula from the XML node *m: getcellindent && Returns the cell indentation *m: getcellnumberformat && Returns the format code for the selected cell *m: getcellnumberformattext && Returns the selected cell numeric format as text *m: getcellrecord && Positions to the xl_cells record; returns true if found, or false if not found *m: getcellstyle && Gets the cell style value *m: getcelltextrotation && Gets the cell text rotation value *m: getcellvalidation && Returns the cell validation settings *m: getcellvalue && Returns the value of the cell *m: getcellwordwrap && Returns the cell word wrap setting *m: getcellxfsid && Returns the Cell XfsId value *m: getcellxfsrecord && Positions the record pointer to xl_cellxfs record; returns true if found, or false if not found *m: getchecksum && Returns the checksum the string *m: getchildnodecount && Returns the number of child nodes *m: getchildnodeelement && Returns the selected child node *m: getcolumnincolrowpair && Returns the column (Ascii value) in a ColRow pair; i.e., returns A from A6 reference *m: getcolumnwidth && Returns the column width *m: getcolwidthkeyexpr && Gets the key expression for c_colwidths *m: getcursorrecord && Gets the specified xl_cursor record; returns true if found, false if not found *m: getcustomnumericformat && Returns the format code for the specified custom numeric format *m: getcustompapersize && Gets the values for the custom paper size *m: getformatkeyexpr && Gets the key expression for t_format *m: getheaderfooterkeyexpr && Gets the key expression for the header footer table record *m: getinlinefontdefinition && Returns the inline formatting definition of cell text for each character group *m: getlastcolumninrow && Returns the last column index in the row *m: getlastrownumber && Returns the last row number in the sheet *m: getmaxcolumnnumber && Returns the max column number for a sheet *m: getnextid && Gets the next sequential Id value *m: getnodeattributevalue && Returns the attribute value *m: getnodecount && Returns the number of nodes to be processed *m: getnodeelement && Gets the string content for the node element *m: getnodeelementvalue && Gets the value assigned to the node element *m: getnumberofsheets && Returns the number of sheets for the given workbook *m: getpapersize && Gets the paper size for the selected sheet *m: getprintorientation && Gets the print orientation for the sheet output *m: getrelationshipfilename && Gets the file name for the R:Id value in the relationships XML *m: getrgbvalues && Gets the specified RGB color value *m: getrowheightkeyexpr && Gets the key expression for the c_rowheights *m: getrowincolrowpair && REturns the row (integer value) in a ColRow pair; i.e., return 6 from A6 reference *m: getrowmaxcolumn && Returns the selected row maximum column *m: getsharedstringid && Gets the Shared Strings Id value for the cell text *m: getsheetname && Gets the sheet name *m: getsheetrecord && Positions the record in xl_sheets; returns true if record found, or false if not found *m: getsheetrowvalues && Returns the cell values for the given row *m: getsheetscale && Gets the sheet printing scale *m: getstringrecord && Positions the record pointer to the selected string record *m: getstringxml && Returns a converted string from XML to text *m: getvalidation && Returns the validation definition *m: getvalidationlist && Returns a list of validations for the workbook/sheet *m: getworkbook && Gets the workbook Id from the name *m: getworkbookfilename && Gets the file name for the workbook index *m: getworkbooksheets && Returns the workbook sheets *m: getxmlheaderfootertext && Returns a XML formatted string for the header and footer text *m: getxmlstring && Gets the string as an XML formatted string *m: initalizeidvalues && Initializes the internal Id values *m: insertcell && Inserts a new cell into the sheet *m: insertcolumn && Inserts a new column into the sheet *m: insertrow && Inserts a new row into the sheet *m: iscellformula && Returns True if cell contains a formula *m: iscellreferenceinvalid && Checks if the cell reference is invalid (outside of limits) *m: isformatstyledefined && Determines if the format is defined as a style *m: isvalidborderstyle && Validates the border style value *m: mergecells && Merges cells together *m: ondestroy && Called by the Destroy() event - user implementation *m: oninit && User code for Init() Event *m: onshowerrormessage && Event for displaying an error message to the user *m: onshowstatusmessage && Event for displaying a wait message to the user *m: opencreatedxlsxfile && Opens the XLSX file via Win32 API default program *m: openxlsxworkbook && Opens the passed Xlsx workbook and loads the internal cursors with the content *m: parsestring && Parses a string based on a specified delimiter *m: readcellvalueformat && Reads the cell value and format for a sheet *m: readexternalrefxml && Reads the External References file *m: readsharedstringsxml && Reads the sharedstrings.xml for opening workbooks *m: readsheetxml && Reads the sheet.xml for opening a workbook *m: readstylesxml && Reads the styles.xml file for opening a workbook *m: removeworkingdirectories && Removes the working directories *m: renamesheet && Renames the selected sheet *m: resetcolumnwidth && Resets the column width to default *m: saveasutf8 && Saves the file as a UTF-8 *m: savegridtoworkbook && Saves the selected grid to a workbook *m: savegridtoworkbookex && Saves the passed grid to a workbook without adding the content to the internal cursors *m: savemultigridtoworkbookex && Same as SaveGridToWorkbookEx() method but handles multiple grids being passed *m: savetabletoworkbook && Saves the table passed (alias) as a workbook sheet *m: savetabletoworkbookex && Creates a new workbook from a table; direct write to XLSX file without loading internal cursors *m: saveworkbook && Saves the selected workbook as an XLSX file *m: saveworkbookas && Saves the selected workbook with the new name *m: setcellalignment && Sets the cell horizontal and vertical alignments *m: setcellalignmentrange && Sets the cell alignment for a range of cells *m: setcellborder *m: setcellborderex *m: setcellborderrange && Sets the cell border for a range of cells *m: setcellfill && Sets the fill color for the cell *m: setcellfillrange && Sets the fill for a range of cells *m: setcellfont && Sets the selected cell font format *m: setcellfontrange && Sets the cell font format for a range of cells *m: setcellformula && Sets the cell formula expression *m: setcellindent && Sets the cell indentation value *m: setcellinlineformattext && Saves the in-line format definition to a cell value *m: setcellnumberdecimals && Sets the number of decimals to display *m: setcellnumberformat && Sets the cell number format *m: setcellnumberformatrange && Sets the number format for a range of cells *m: setcellstyle && Sets the cell style *m: setcellstylerange && Sets the cell style for a range of cells *m: setcelltextrotation && Sets the cell text rotation value *m: setcellvalidation && Adds a cell validation *m: setcellvalue && Sets the cell value *m: setcellwordwrap && Sets the cell word-wrapping value *m: setcellwordwraprange && Sets the word wrap for a range of cells *m: setcolumnbestfit && Set the column to best fit *m: setcolumnwidth && Sets the column width *m: setcolumnwidthrange && Sets the column width for a range of columns *m: setcustompapersize && Sets the paper size based on custom dimensions *m: setdefaultborder && Sets the default border style for the workbook *m: setdefaultfill && Sets the default fill for the workbook *m: setdefaultfont && Sets the default font for the workbook *m: setheaderfootersetup && Sets the header and footer setup for the sheet *m: setheaderfootertext && Sets the header/footer text for the sheet *m: setlastid && Sets the last used Id Value for strings, borders, fills, fonts, and cellxfs *m: setpapersize && Sets the paper size for the selected sheet *m: setprintfittoheight && Number of vertical pages to fit on for printing *m: setprintfittowidth && Number of horizontal pages to fit on for printing *m: setprintorientation && Sets the printer orientation for sheet output *m: setrowheight && Sets the row height *m: setrowheightrange && Sets the row height for a range of rows *m: setrowmaxcolumn && Sets the value for the maximum cell column in a row *m: setsheetmargins && Sets the sheet margin values *m: setsheetscale && Sets the print scale; must be between 10 and 400; i.e. 10=10%, 100=100%, etc. *m: setsheetvisibility && Sets the sheet visibility *m: ttoc3 && Equlivalent of TTOC() function for pre VFP9 support *m: unfreezepanes && Removes the pane freeze from the sheet *m: unmergedcells && Unmerges merged cells *m: writeasinlineformattedstring && Writes the string as formatted in-line *m: writeasinlinestring && Writes the value as an inlineStr value *m: writedirectcellformattedvalue && WriteDirectCellFormattedValue *m: writedirectcellvalue && Writes the cell value directly to the sheets xml *m: writedirectxmls && Writes the workbook XMLs for direct table/grid to workbook output *m: writerelationshipsxml && Writes the relationships xml file *m: writesheetxmls && Writes the Sheet XML files *m: writestringsxml && Writes the sharedStrings XML *m: writestylesxml && Writes the styles.xml support file *m: writesupportxmls && Writes the [Content_Types].xml, .rels, core.xml, workbook.xml.rels and app.xml files *m: writeworkbookxml && Writes the workbook XML *p: autotrimsheetname && Indicates to auto-trim sheet name to max length ***Boolean *p: codepage && CodePage to use for the Strings cursor *p: companyname && Company Name *p: creatorname && Creator Name *p: debug && Sets debugging mode ***Boolean *p: declarewinapi && Flag to execute the DeclareDLL method in the Init() ***Boolean *p: defaultfont && Workbook Default Font *p: defaultfontsize && Default font size ***Integer *p: defaultsheetname && Default sheet name (language specific) *p: errorlevelid && Error level Id ***Integer *p: excelxlsxrelease && Release version of Class ***Integer *p: oxdom && XML DOM Object *p: savecurrencyasnumeric && Flag to save a currency value as a numeric rather than currency in the spreadsheet; will convert the value to four decimal places ***Boolean *p: subject && Subject of Workbook (stored in properties) *p: title && Title of workbook (stored in properties) *p: truefalsevalue && The boolean value as displayed in Excel delimited by a pipe symbol *p: username && User Name *a: lastborderid[1,2] && Stores the last used border Id for a workbook *a: lastcellxfsid[1,2] && Stores the last used CellXfs Id for a workbook *a: lastfillid[1,2] && Stores the last used fill Id for a workbook *a: lastfontid[1,2] && Stores the last used font Id for a workbook *a: lastindexcolorid[1,2] && Last used IndexedColor Id *a: lastmrucolorid[1,2] && Last used mruColor Id value *a: lastnumfmtid[1,2] && Last used NumFmt Id *a: lastrelationid[1,2] && Last used Relationship Id *a: lastsheetid[1,2] && Last used sheet Id *a: laststringid[1,2] && Stores the last used string Id for a workbook *a: stringndx[1,0] && Returns the next string index value by workbook ***Integer *p: _memberdata && XML Metadata for customizable properties * PROTECTED Destroy,Init * AutoSize = .T. autotrimsheetname = .T. Caption = "clsVFPxWorkbookXLSX" codepage = 0 companyname = VFPxWorkbookXLSX creatorname = VFPxWorkbookXLSX debug = .F. declarewinapi = .T. defaultfont = Calibri defaultfontsize = 11 defaultsheetname = Sheet errorlevelid = 0 excelxlsxrelease = 31 Height = 17 Name = "vfpxworkbookxlsx" oxdom = savecurrencyasnumeric = .F. subject = title = truefalsevalue = Yes|No username = VFPxWorkbookXLSX Visible = .F. Width = 129 _memberdata = * PROTECTED PROCEDURE addclassdefinednumericformats && Adds pre-defined numeric cell formats LPARAMETERS tnWB, tnFormatId LOCAL llAdded, lcTextFormat, lcXMLFormat DO CASE CASE tnFormatId = CELL_FORMAT_CURRENCY_RED lcTextFormat = '"$"#,##0.00;[Red]("$"#,##0.00)' lcXMLFormat = this.GetXMLString(lcTextFormat) INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, CELL_FORMAT_CURRENCY_RED, lcXMLFormat, lcTextFormat, False) llAdded = True CASE tnFormatId = CELL_FORMAT_ACC_CURR_POUNDS lcXMLFormat = '_-[$£-809]* #,##0.00_-;-[$£-809]* #,##0.00_-;_-[$£-809]* "-"??_-;_-@_-' lcTextFormat = '"£"#,##0.00;[Red]("£"#,##0.00)' INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, CELL_FORMAT_ACC_CURR_POUNDS, lcXMLFormat, lcTextFormat, False) llAdded = True CASE tnFormatId = CELL_FORMAT_ACC_CURR_EURO lcXMLFormat = '_-[$€-2]* .00_-;-[$€-2]* .00_-;_-[$€-2]* "-"??_-;_-@_-' lcTextFormat = '"€"#,##0.00;[Red]("€"#,##0.00)' INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, CELL_FORMAT_ACC_CURR_EURO, lcXMLFormat, lcTextFormat, False) llAdded = True CASE tnFormatId = CELL_FORMAT_CURR_POUNDS_RED lcXMLFormat = '[$£-809]#,##0.00;[Red]\-[$£-809]#,##0.00' lcTextFormat = '"£"#,##0.00;[Red]("£"#,##0.00)' INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, CELL_FORMAT_CURR_POUNDS_RED, lcXMLFormat, lcTextFormat, False) llAdded = True CASE tnFormatId = CELL_FORMAT_CURR_EURO_RED lcXMLFormat = '[$€-2]\ #,##0.00_);[Red]\([$€-2]\ #,##0.00\)' lcTextFormat = '"€"#,##0.00;[Red]("€"#,##0.00)' INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, CELL_FORMAT_CURR_EURO_RED, lcXMLFormat, lcTextFormat, False) llAdded = True OTHERWISE llAdded = False ENDCASE RETURN llAdded ENDPROC PROCEDURE addcustomnumericformat && Adds a new custom defined numeric format LPARAMETERS tnWB, tcPosFormat, tcNegFormat, tcZeroFormat, tcTextFormat, tlApplyDec LOCAL lnId, lcFormatCode, lnNdx, lcSetPoint, lcSeparator IF VARTYPE(tcPosFormat) != "C" RETURN 0 ENDIF DO CASE CASE PCOUNT() = 1 tcNegFormat = "" tcZeroFormat = "" tcTextFormat = "" tlApplyDec = False CASE PCOUNT() = 2 tcZeroFormat = "" tcTextFormat = "" tlApplyDec = False CASE PCOUNT() = 3 tcTextFormat = "" tlApplyDec = False CASE PCOUNT() = 4 tlApplyDec = False ENDCASE IF VARTYPE(tcNegFormat) != "C" tcNegFormat = "" ENDIF IF VARTYPE(tcZeroFormat) != "C" tcZeroFormat = "" ENDIF IF VARTYPE(tcTextFormat) != "C" tcTextFormat = "" ENDIF IF OCCURS(";", tcPosFormat) > 0 RETURN 0 ENDIF IF OCCURS(";", tcNegFormat) > 0 RETURN 0 ENDIF IF OCCURS(";", tcZeroFormat) > 0 RETURN 0 ENDIF IF OCCURS(";", tcTextFormat) > 0 RETURN 0 ENDIF *-* If not US standard for separator and decimal point, then change to US standard lcSetPoint = SET("POINT") lcSeparator = SET("SEPARATOR") IF lcSetPoint != "." .OR. lcSeparator != "," tcPosFormat = CHRTRAN(tcPosFormat, lcSetPoint, TAB) tcPosFormat = CHRTRAN(tcPosFormat, lcSeparator, CR) tcPosFormat = CHRTRAN(tcPosFormat, TAB, ".") tcPosFormat = CHRTRAN(tcPosFormat, CR, ",") tcNegFormat = CHRTRAN(tcNegFormat, lcSetPoint, TAB) tcNegFormat = CHRTRAN(tcNegFormat, lcSeparator, CR) tcNegFormat = CHRTRAN(tcNegFormat, TAB, ".") tcNegFormat = CHRTRAN(tcNegFormat, CR, ",") tcZeroFormat = CHRTRAN(tcZeroFormat, lcSetPoint, TAB) tcZeroFormat = CHRTRAN(tcZeroFormat, lcSeparator, CR) tcZeroFormat = CHRTRAN(tcZeroFormat, TAB, ".") tcZeroFormat = CHRTRAN(tcZeroFormat, CR, ",") tcTextFormat = CHRTRAN(tcTextFormat, lcSetPoint, TAB) tcTextFormat = CHRTRAN(tcTextFormat, lcSeparator, CR) tcTextFormat = CHRTRAN(tcTextFormat, TAB, ".") tcTextFormat = CHRTRAN(tcTextFormat, CR, ",") ENDIF *-* Build expression from parts lcFormatCode = tcPosFormat IF !EMPTY(tcNegFormat) lcFormatCode = lcFormatCode + ";" + tcNegFormat ENDIF IF !EMPTY(tcZeroFormat) lcFormatCode = lcFormatCode + ";" + tcZeroFormat ENDIF IF !EMPTY(tcTextFormat) lcFormatCode = lcFormatCode + ";" + tcTextFormat ENDIF lnId = this.GetNextId(tnWB, "xl_numfmts") INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, lnId, this.GetXMLString(lcFormatCode), lcFormatCode, tlApplyDec) RETURN lnId ENDPROC PROCEDURE addindexcolor && Adds a new indexed color definition LPARAMETERS tnWB, tnRGBColor LOCAL lnIndexId, lcHexColor IF PCOUNT() != 2 .OR. VARTYPE(tnRGBColor) != "N" RETURN 0 ENDIF lcHexColor = this.ConvertColorToHex(tnRGBColor) IF SEEK(BINTOC(tnWB)+lcHexColor, "xl_ndxcolors", "rgbcolor") lnIndexId = xl_ndxcolors.indexid ELSE lnIndexId = this.GetNextId(tnWB, "xl_ndxcolors") INSERT INTO xl_ndxcolors (workbook, indexid, rgbcolor) VALUES (tnWB, lnIndexId, lcHexColor) ENDIF RETURN lnIndexId ENDPROC PROCEDURE addinlinefontobject && Adds an object for setting the inline formatting of cell text LPARAMETERS toInline, tnBeg, tnLen, tcFontName, tnFontSize, tnFontColor, tlFontBold, tlFontItalic, tcULine, tlStrkThru, tlSubscript, tlSuperscript LOCAL loCharacter IF PCOUNT() < 4 RETURN .NULL. ENDIF IF VARTYPE(toInline) != "O" RETURN .NULL. ENDIF DO CASE CASE PCOUNT() = 4 tnFontSize = 10 tnFontColor = RGB(0,0,0) tlFontBold = False tlFontItalic = False tcULine = UNDERLINE_NONE tlStrkThru = False tlSubscript = False tlSuperscript = False CASE PCOUNT() = 5 tnFontColor = RGB(0,0,0) tlFontBold = False tlFontItalic = False tcULine = UNDERLINE_NONE tlStrkThru = False tlSubscript = False tlSuperscript = False CASE PCOUNT() = 6 tlFontBold = False tlFontItalic = False tcULine = UNDERLINE_NONE tlStrkThru = False tlSubscript = False tlSuperscript = False CASE PCOUNT() = 7 tlFontItalic = False tcULine = UNDERLINE_NONE tlStrkThru = False tlSubscript = False tlSuperscript = False CASE PCOUNT() = 8 tcULine = UNDERLINE_NONE tlStrkThru = False tlSubscript = False tlSuperscript = False CASE PCOUNT() = 9 tlStrkThru = False tlSubscript = False tlSuperscript = False CASE PCOUNT() = 10 tlSubscript = False tlSuperscript = False CASE PCOUNT() = 11 tlSuperscript = False ENDCASE loCharacter = CREATEOBJECT("Empty") ADDPROPERTY(loCharacter, "BegPos", tnBeg) ADDPROPERTY(loCharacter, "Length", tnLen) ADDPROPERTY(loCharacter, "FontName", tcFontName) ADDPROPERTY(loCharacter, "FontSize", tnFontSize) ADDPROPERTY(loCharacter, "FontBold", tlFontBold) ADDPROPERTY(loCharacter, "FontItalic", tlFontItalic) ADDPROPERTY(loCharacter, "FontColor", tnFontColor) ADDPROPERTY(loCharacter, "Underline", tcULine) ADDPROPERTY(loCharacter, "StrikeThru", tlStrkThru) ADDPROPERTY(loCharacter, "SubScript", tlSubscript) ADDPROPERTY(loCharacter, "SuperScript", tlSuperscript) toInline.Count = toInline.Count + 1 DIMENSION toInline.Characters[toInline.Count] toInline.Characters[toInline.Count] = loCharacter RETURN toInline ENDPROC PROCEDURE addmrucolor && Adds a custom defined MRU color to the workbook LPARAMETERS tnWB, tnRGBColor LOCAL lnIndexId, lcHexColor IF PCOUNT() != 2 .OR. VARTYPE(tnRGBColor) != "N" RETURN 0 ENDIF lcHexColor = this.ConvertColorToHex(tnRGBColor) IF SEEK(BINTOC(tnWB)+lcHexColor, "xl_mrucolors", "rgbcolor") lnIndexId = xl_mrucolors.indexid ELSE lnIndexId = this.GetNextId(tnWB, "xl_mrucolors") INSERT INTO xl_mrucolors (workbook, indexid, rgbcolor) VALUES (tnWB, lnIndexId, lcHexColor) ENDIF RETURN lnIndexId ENDPROC PROCEDURE addnamedrange && Adds a name range to the workbook LPARAMETERS tnWB, tnSheet, tcName, tnScope, tcComment, tnBegRow, tnBegCol, tnEndRow, tnEndCol LOCAL lcRangeName IF PCOUNT() < 8 RETURN "" ENDIF IF VARTYPE(tcName) != "C" .OR. LEN(tcName) > 50 RETURN "" ENDIF IF VARTYPE(tnScope) != "N" tnScope = 0 ENDIF IF VARTYPE(tcComment) != "C" tcComment = "" ENDIF IF LEN(tcComment) > 254 RETURN "" ENDIF IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN "" ENDIF lcRangeName = CHRTRAN(ALLTRIM(tcName), " !@#$%^&*()+={}[]|<>,.'?/" + CHR(34), REPLICATE("_", 25)) IF !ISALPHA(lcRangeName) .AND. !INLIST(LEFT(lcRangeName, 1), "_", "\") lcRangeName = "_" + lcRangeName ENDIF IF SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") .AND. !SEEK(BINTOC(tnWB)+PADL(lcRangeName, 254, " "), "xl_namerange", "wbrname") INSERT INTO xl_namerange (workbook, sheet, rname, scope, comment, begrow, begcol, endrow, endcol) ; VALUES (tnWB, tnSheet, lcRangeName, tnScope, tcComment, tnBegRow, tnBegCol, tnEndRow, tnEndCol) ELSE lcRangeName = "" ENDIF RETURN lcRangeName ENDPROC PROCEDURE addnumericformat && Adds a numeric format expression to be used LPARAMETERS tnWB, tcFormatCode LOCAL lcPosCode, lcNegCode, lcZerCode IF PCOUNT() < 2 RETURN 0 ENDIF IF VARTYPE(tnWB) != "N" .AND. tnWB > 0 RETURN 0 ENDIF IF VARTYPE(tcFormatCode) != "C" RETURN 0 ENDIF lcPosCode = this.ParseString(tcFormatCode, 1, ";") lcNegCode = this.ParseString(tcFormatCode, 2, ";") lcZerCode = this.ParseString(tcFormatCode, 3, ";") RETURN this.AddCustomNumericFormat(tnWB, lcPosCode, lcNegCode, lcZerCode) ENDPROC PROCEDURE addsheet && Adds a new sheet to the workbook LPARAMETERS tnWB, tcSheetName, tnState LOCAL lnShId, lnRelId lnShId = 0 IF PCOUNT() > 0 .AND. SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") lnShId = this.GetNextId(tnWB, "xl_sheets") DO CASE CASE PCOUNT() = 0 CASE PCOUNT() = 1 tcSheetName = "Sheet" + TRANSFORM(lnShId + 1) && Bug fix identified by Dan Lauer tnState = VISIBLE_SHEET_STATE CASE PCOUNT() = 2 IF VARTYPE(tcSheetName) != "C" tcSheetName = "Sheet" + TRANSFORM(lnShId + 1) ENDIF tnState = VISIBLE_SHEET_STATE OTHERWISE IF VARTYPE(tcSheetName) != "C" tcSheetName = "Sheet" + TRANSFORM(lnShId + 1) ENDIF IF VARTYPE(tnState) != "N" tnState = VISIBLE_SHEET_STATE ENDIF ENDCASE IF EMPTY(tcSheetName) tcSheetName = "Sheet" + TRANSFORM(lnShId + 1) ENDIF tcSheetName = CHRTRAN(tcSheetName, ":\/?*", "_____") IF LEN(tcSheetName) > LIMITS_MAX_SH_NAME IF this.AutoTrimSheetName tcSheetName = LEFT(ALLTRIM(tcSheetName), LIMITS_MAX_SH_NAME) ELSE this.SetLastId(tnWB, lnShId-1, "xl_sheets") RETURN 0 ENDIF ENDIF IF SEEK(BINTOC(tnWB)+UPPER(PADR(tcSheetName, LEN(xl_sheets.shname))), "xl_sheets", "shname") && Change recommendation by Doug Hennig lnShId = 0 ELSE INSERT INTO xl_sheets (workbook, sheet, shname, state, mleft, mright, mtop, mbot, mheader, mfooter, shdeleted, xsplit, ysplit, prnorient, ; papersize, paperwidth, paperheight, scale, fittowidth, fittoheight) ; VALUES (tnWB, lnShId, tcSheetName, tnState, 0.75, 0.75, 0.75, 0.75, 0.3, 0.3, False, 0, 0, PORTRAIT_PRINT_ORIENTATION, 0, 0, 0, 100, 0, 0) lnRelId = this.GetNextId(tnWB, "xl_relationships") INSERT INTO xl_relationships (workbook, sheet, relid, reltype, target) VALUES (tnWB, lnShId, lnRelId, "worksheet", "worksheets/sheet" + TRANSFORM(lnShId) + ".xml") ENDIF ENDIF RETURN lnShId ENDPROC PROTECTED PROCEDURE addstringvalue && Adds a string value to the internal cursor LPARAMETERS tnWB, tcString, tlInLine LOCAL lcStringXml, lnStringId, llPresrvSp, lcCheckSum IF tlInLine llPresrvSp = IIF(LEFT(tcString, 1) = " ", True, False) lcStringXml = this.GetXMLString(tcString) lnStringId = this.GetNextId(tnWB, "xl_strings") lcCheckSum = this.GetCheckSum(tcString) INSERT INTO xl_strings (id, workbook, checksum, stringxml, stringval, presvspace, formatted) ; VALUES (lnStringId, tnWB, lcCheckSum, lcStringXml, tcString, llPresrvSp, True) ELSE IF this.GetStringRecord(tnWB, tcString) .AND. xl_strings.formatted = False lnStringId = xl_strings.id ELSE llPresrvSp = IIF(LEFT(tcString, 1) = " " .OR. RIGHT(tcString, 1) = " ", True, False) lcStringXml = this.GetXMLString(tcString) lnStringId = this.GetNextId(tnWB, "xl_strings") lcCheckSum = this.GetCheckSum(tcString) INSERT INTO xl_strings (id, workbook, checksum, stringxml, stringval, presvspace, formatted) ; VALUES (lnStringId, tnWB, lcCheckSum, lcStringXml, tcString, llPresrvSp, False) ENDIF ENDIF RETURN lnStringId ENDPROC PROCEDURE addstyleborders && Adds to the cell style a border definition LPARAMETERS tnWB, tnCellXfsId, tnBorders, tcStyle, tnColor LOCAL lnDiagDn, lnDiagUp, lcLStyle, lnLColor, lcRStyle, lnRColor, lcTStyle, lnTColor, lcBStyle, lnBColor LOCAL lcDStyle, lnDColor, lnBorderId IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tnBorders) != 'N' .OR. EMPTY(tnBorders) .OR. !BETWEEN(tnBorders, 0, 63) tnBorders = 0 ENDIF IF !this.IsValidBorderStyle(tcStyle) tcStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnColor) != 'N' .OR. !BETWEEN(tnColor, 0, RGB(255,255,255)) .OR. EMPTY(tnColor) tnColor = RGB(0, 0, 0) ENDIF STORE 0 TO lnDiagDn, lnDiagUp STORE RGB(0,0,0) TO lnLColor, lnRColor, lnTColor, lnBColor, lnDColor STORE BORDER_STYLE_NONE TO lcLStyle, lcRStyle, lcTStyle, lcBStyle, lcDStyle IF BITTEST(tnBorders, 0) lcLStyle = tcStyle lnLColor = tnColor ENDIF IF BITTEST(tnBorders, 1) lcRStyle = tcStyle lnRColor = tnColor ENDIF IF BITTEST(tnBorders, 2) lcTStyle = tcStyle lnTColor = tnColor ENDIF IF BITTEST(tnBorders, 3) lcBStyle = tcStyle lnBColor = tnColor ENDIF IF BITTEST(tnBorders, 4) lcDStyle = tcStyle lnDColor = tnColor lnDiagDn = 1 ENDIF IF BITTEST(tnBorders, 5) lcDStyle = tcStyle lnDColor = tnColor lnDiagUp = 1 ENDIF IF this.GetBordersRecord(tnWB, lcLStyle, lnLColor, lcRStyle, lnRColor, lcTStyle, lnTColor, lcBStyle, lnBColor, lcDStyle, lnDColor, lnDiagDn, lnDiagUp) lnBorderId = xl_borders.id ELSE lnBorderId = this.GetNextId(tnWB, 'xl_borders') INSERT INTO xl_borders (workbook, id, lstyle, lcolor, rstyle, rcolor, tstyle, tcolor, bstyle, bcolor, dstyle, dcolor, diagdn, diagup) ; VALUES (tnWB, lnBorderId, lcLStyle, lnLColor, lcRStyle, lnRColor, lcTStyle, lnTColor, lcBStyle, lnBColor, lcDStyle, lnDColor, lnDiagDn, lnDiagUp) ENDIF *-* Set the border id to the style definition REPLACE xl_cellxfs.borderid WITH lnBorderId IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE addstylefill && Adds to the cell style a fill definition LPARAMETERS tnWB, tnCellXfsId, tnFColor, tnBColor, tcPatternType LOCAL lnFillId, lnFIndex, lnBIndex DO CASE CASE PCOUNT() < 3 RETURN False CASE PCOUNT() = 3 tnBColor = tnFColor tcPatternType = FILL_STYLE_SOLID CASE PCOUNT() = 4 tcPatternType = FILL_STYLE_SOLID ENDCASE IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tnFColor) = 'N' .AND. BETWEEN(tnFColor, 0, RGB(255, 255, 255)) tnFColor = FLOOR(tnFColor) lnFIndex = 0 ELSE tnFColor = 0 lnFIndex = 64 ENDIF IF VARTYPE(tnBColor) = 'N' .AND. BETWEEN(tnBColor, 0, RGB(255, 255, 255)) tnBColor = FLOOR(tnBColor) lnBIndex = 0 ELSE tnBColor = tnFColor lnBIndex = lnFIndex ENDIF IF VARTYPE(tcPatternType) != "C" .OR. EMPTY(tcPatternType) tcPatternType = FILL_STYLE_SOLID ENDIF *-* Get the fill record id IF SEEK(BINTOC(tnWB)+BINTOC(tnFColor)+BINTOC(tnBColor)+tcPatternType, "xl_fills", "fillcolor") lnFillId = xl_fills.id REPLACE xl_fills.theme WITH 0, ; xl_fills.tint WITH 0, ; xl_fills.fgindexed WITH lnFIndex, ; xl_fills.bgindexed WITH lnBIndex IN xl_fills ELSE lnFillId = this.GetNextId(tnWB, 'xl_fills') INSERT INTO xl_fills (workbook, id, fgcolor, bgcolor, patttype, theme, tint, fgindexed, bgindexed) ; VALUES (tnWB, lnFillId, tnFColor, tnBColor, tcPatternType, 0, 0, lnFIndex, lnBIndex) ENDIF *-* Set the fill id to the style definition REPLACE xl_cellxfs.fillid WITH lnFillId IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE addstylefont && Adds to the cell style a font definition LPARAMETERS tnWB, tnCellXfsId, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos LOCAL lnFontId IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tcFName) != 'C' .OR. EMPTY(tcFName) tcFName = 'Calibri' ENDIF tcFName = PROPER(ALLTRIM(tcFName)) IF VARTYPE(tnFSize) != 'N' .OR. EMPTY(tnFSize) .OR. tnFSize < 0.5 tnFSize = 11 ELSE tnFSize = INT(tnFSize) ENDIF IF VARTYPE(tlBold) != 'L' tlBold = False ENDIF IF VARTYPE(tlItalic) != 'L' tlItalic = False ENDIF IF VARTYPE(tnFColor) = 'N' .AND. BETWEEN(tnFColor, 0, RGB(255, 255, 255)) tnFColor = FLOOR(tnFColor) ELSE tnFColor = RGB(0, 0, 0) ENDIF IF VARTYPE(tlStrikThr) != 'L' tlStrikThr = False ENDIF IF VARTYPE(tcULine) != 'C' .OR. !INLIST(tcULine, UNDERLINE_SINGLE, UNDERLINE_DOUBLE, UNDERLINE_SINGLEACCOUNTING, UNDERLINE_DOUBLEACCOUNTING, UNDERLINE_NONE) tcULine = UNDERLINE_NONE ENDIF IF VARTYPE(tcVPos) != 'C' .OR. !INLIST(tcVPos, FONT_VERTICAL_BASELINE, FONT_VERTICAL_SUBSCRIPT, FONT_VERTICAL_SUPERSCRIPT) tcVPos = FONT_VERTICAL_BASELINE ENDIF *-* Get the font record id IF SEEK(BINTOC(tnWB)+PADR(tcFName, 100) + STR(tnFSize, 5, 1) + TRANSFORM(tlBold) + TRANSFORM(tlItalic) + PADL(tnFColor, 15) + PADR(tcULine, 16) + ; TRANSFORM(tlStrikThr) + PADR(tcVPos, 11), "xl_fonts", "cellformat") lnFontId = xl_fonts.id REPLACE xl_fonts.theme WITH 0, ; xl_fonts.tint WITH 0, ; xl_fonts.indexed WITH 0 IN xl_fonts ELSE lnFontId = this.GetNextId(tnWB, 'xl_fonts') INSERT INTO xl_fonts (workbook, id, fname, fsize, fbold, fitalic, fcolor, uline, strkthr, fvpos) ; VALUES (tnWB, lnFontId, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos) ENDIF *-* Set the font id to the style definition REPLACE xl_cellxfs.fontid WITH lnFontId IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE addstylehorizalignment && Adds to the cell style horizontal cell alignment LPARAMETERS tnWB, tnCellXfsId, tcHorizAlign IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tcHorizAlign) = 'C' .AND. INLIST(tcHorizAlign, CELL_HORIZ_ALIGN_LEFT, CELL_HORIZ_ALIGN_RIGHT, CELL_HORIZ_ALIGN_CENTER) REPLACE xl_cellxfs.halign WITH tcHorizAlign IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ELSE RETURN False ENDIF ENDPROC PROCEDURE addstyleindent && Adds to the style indent definition LPARAMETERS tnWB, tnCellXfsId, tnIndent IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tnIndent) = 'N' REPLACE xl_cellxfs.indent WITH tnIndent IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ELSE RETURN False ENDIF ENDPROC PROCEDURE addstylenumericformat && Adds to the style definition numeric format LPARAMETERS tnWB, tnCellXfsId, tnNumFmtId LOCAL lnNumFmtId IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") DO CASE CASE VARTYPE(tnNumFmtId) != 'N' RETURN False CASE tnNumFmtId < START_NUMERIC_FORMAT_ID lnNumFmtId = tnNumFmtId CASE tnNumFmtId >= START_NUMERIC_FORMAT_ID IF SEEK(BINTOC(tnWB)+BINTOC(tnNumFmtId), "xl_numfmts", "id") lnNumFmtId = xl_numfmts.id ELSE IF !this.AddClassDefinedNumericFormats(tnWB, tnNumFmtId) RETURN False ENDIF lnNumFmtId = tnNumFmtId ENDIF OTHERWISE RETURN False ENDCASE REPLACE xl_cellxfs.numfmtid WITH lnNumFmtId IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE addstyletextrotation && Adds to the style definition text rotation LPARAMETERS tnWB, tnCellXfsId, tnRotation IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tnRotation) = 'N' .AND. BETWEEN(tnRotation, -90, 90) REPLACE xl_cellxfs.rotation WITH tnRotation IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ELSE RETURN False ENDIF ENDPROC PROCEDURE addstylevertalignment && Adds to the cell style vertical cell alignment LPARAMETERS tnWB, tnCellXfsId, tcVertAlign IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tcVertAlign) = 'C' .AND. INLIST(tcVertAlign, CELL_VERT_ALIGN_TOP, CELL_VERT_ALIGN_BOTTOM, CELL_VERT_ALIGN_CENTER) REPLACE xl_cellxfs.valign WITH tcVertAlign IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ELSE RETURN False ENDIF ENDPROC PROCEDURE addstylewordwrap && Adds to the style definition word wrap LPARAMETERS tnWB, tnCellXfsId, tlWordWrap IF PCOUNT() < 3 RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF VARTYPE(tlWordWrap) = 'L' REPLACE xl_cellxfs.wraptext WITH IIF(tlWordWrap, 1, 0) IN xl_cellxfs RETURN True ELSE RETURN False ENDIF ELSE RETURN False ENDIF ENDPROC PROCEDURE cellformatpainter && Copies the formatting of a source cell to other cells LPARAMETERS tnWB, tnSheet, tnSrcRow, tnSrcCol, tnBegRow, tnBegCol, tnEndRow, tnEndCol LOCAL lnCellXfs, lnNumDec, llReturn, lnRow, lnCol DO CASE CASE PCOUNT() < 6 RETURN False CASE PCOUNT() = 6 tnEndRow = tnBegRow tnEndCol = tnBegCol CASE PCOUNT() = 7 tnEndCol = tnBegCol ENDCASE IF this.GetCellRecord(tnWB, tnSheet, tnSrcRow, tnSrcCol) lnCellXfs = xl_cells.cellxfs lnNumDec = xl_cells.numdec FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF this.GetCellRecord(tnWB, tnSheet, lnRow, lnCol) REPLACE xl_cells.cellxfs WITH lnCellXfs, ; xl_cells.numdec WITH lnNumDec IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, lnRow, lnCol, DATA_TYPE_NONE, lnCellXfs, False, lnNumDec, 0) ENDIF ENDFOR ENDFOR llReturn = True ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE cellrefasciitoindex && Converts a 'AA444' cell reference to the row and column index values LPARAMETERS tcCellRef LOCAL lnCellCol, lnNdx, lnCellRow, loCellRef lnCellCol = this.ColumnAsciiToIndex(tcCellRef) lnCellRow = 0 FOR lnNdx=1 TO LEN(tcCellRef) IF ISDIGIT(SUBSTR(tcCellRef, lnNdx)) lnCellRow = INT(VAL(SUBSTR(tcCellRef, lnNdx))) EXIT ENDIF ENDFOR loCellRef = CREATEOBJECT("Empty") ADDPROPERTY(loCellRef, "Column", lnCellCol) ADDPROPERTY(loCellRef, "Row", lnCellRow) RETURN loCellRef ENDPROC PROCEDURE clearcellvalidation && Clears/deletes the named range from the workbook LPARAMETERS tnWB, tcName IF PCOUNT() < 2 RETURN False ENDIF IF VARTYPE(tcName) != "C" RETURN False ENDIF IF SEEK(BINTOC(tnWB)+PADL(tcName, 254, " "), "xl_namerange", "wbrname") DELETE IN xl_namerange llReturn = True ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE clearcellvalue && Clears the cell value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL llReturn IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.celldeleted WITH True IN xl_cells llReturn = True ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE columnasciitoindex && Converts Excel Ascii column value to index value LPARAMETERS tcColIndex LOCAL lnIndex, lnNdx, lnChr lnIndex = 0 FOR lnNdx=1 TO LEN(tcColIndex) lnChr = ASC(UPPER(SUBSTR(tcColIndex, lnNdx, 1))) IF BETWEEN(lnChr, 65, 90) lnIndex = (lnChr - 64) + (lnIndex * 26) ELSE EXIT ENDIF ENDFOR RETURN lnIndex ENDPROC PROCEDURE columnindextoascii && Gets the column ASCII code for the column index LPARAMETERS tnCol LOCAL lnRemCol, lcColumn, lnPartCol IF PCOUNT() = 0 .OR. VARTYPE(tnCol) != "N" RETURN "" ENDIF TRY lnRemCol = tnCol lcColumn = "" DO WHILE lnRemCol > 0 lnPartCol = MOD(lnRemCol, 26) IF lnPartCol = 0 lnPartCol = 26 ENDIF lnRemCol = (lnRemCol - lnPartCol) / 26 lcColumn = CHR(lnPartCol + 64) + lcColumn ENDDO CATCH TO loException SET STEP ON ENDTRY RETURN lcColumn ENDPROC PROTECTED PROCEDURE convertcolortohex && Converts a color value (integer) to Hex representation LPARAMETERS tnColor LOCAL lnRed, lnGreen, lnBlue, lcHexRed, lcHexGreen, lcHexBlue lnRed = this.GetRGBValues(tnColor, 'R') lnGreen = this.GetRGBValues(tnColor, 'G') lnBlue = this.GetRGBValues(tnColor, 'B') lcHexRed = RIGHT(TRANSFORM(lnRed, '@0'), 2) lcHexGreen = RIGHT(TRANSFORM(lnGreen, '@0'), 2) lcHexBlue = RIGHT(TRANSFORM(lnBlue, '@0'), 2) RETURN "FF" + UPPER(lcHexRed + lcHexGreen + lcHexBlue) ENDPROC PROTECTED PROCEDURE converthexstringtonumeric && ConvertHexStringToNumeric LPARAMETERS tcHexNum LOCAL lcValue IF EMPTY(tcHexNum) RETURN 0 ENDIF IF LEN(tcHexNum) > 6 tcHexNum = SUBSTR(tcHexNum, 3) ENDIF tcHexNum = UPPER(ALLTRIM(tcHexNum)) tcHexNum = RIGHT(tcHexNum, 2) + SUBSTR(tcHexNum, 3, 2) + LEFT(tcHexNum, 2) lcValue = "0x" + tcHexNum RETURN EVAL(lcValue) ENDPROC PROCEDURE convertpixelstoexcelunits && Converts Pixel measurement to Excel measurement LPARAMETERS tnPixels RETURN tnPixels * 0.152542 ENDPROC PROTECTED PROCEDURE createexcelfile && Creates the Excel file from the components LPARAMETERS tcTempPath, tcFilePath, tcWBName LOCAL loShell, loFolder, lcZipFile, loException, loFile, lnCountBefore, lcFile, lcZipPath, lnCount, lhFile lcZipPath = ALLTRIM(tcFilePath) IF EMPTY(lcZipPath) lcZipPath = SYS(5) + SYS(2003) ENDIF lcZipFile = ADDBS(lcZipPath) + FORCEEXT(ALLTRIM(tcWBName), "zip") *-* Delete any prior file with same Excel name IF FILE(FORCEEXT(lcZipFile, "xlsx")) TRY ERASE (FORCEEXT(lcZipFile, "xlsx")) llError = False CATCH TO loException this.ErrorLevelId = 10 RAISEEVENT(this, "OnShowErrorMessage", 10, "Error - unable to delete existing file" + CR + loException.Message) llError = True ENDTRY IF llError RETURN False ENDIF ENDIF *-* Validate that the file name and path are valid TRY lhFile = FCREATE(lcZipFile, 0) FCLOSE(lhFile) CATCH TO loException this.ErrorLevelId = 11 RAISEEVENT(this, "OnShowErrorMessage", 11, "CreateExcelFile - Failed to create Zip file"+ CR + loException.Message) RETURN False ENDTRY *-* Create base zip file STRTOFILE(CHR(80)+CHR(75)+CHR(5)+CHR(6)+REPLICATE(CHR(0), 18), lcZipFile, 0) loShell = CREATEOBJECT("shell.application") loFolder = loShell.NameSpace(tcTempPath).Items *-* Add the files to the zip IF OS(3)<'6' .OR. OS(3)='6' .AND. OS(4)<'1' TRY FOR EACH loFile IN loFolder loShell.NameSpace(lcZipFile).MoveHere(loFile, FOF_SILENT) apiSleep(100) ENDFOR CATCH TO loException SET STEP ON ENDTRY llErr = True DO WHILE llErr TRY apiMoveFile(lcZipFile, FORCEEXT(lcZipFile, "xlsx")) llErr = False CATCH apiSleep(100) ENDTRY ENDDO ELSE TRY FOR EACH loFile IN loFolder lnCountBefore = loShell.NameSpace(tcTempPath).Items.Count loShell.NameSpace(lcZipFile).MoveHere(loFile, FOF_SILENT) DO WHILE lnCountBefore = loShell.NameSpace(tcTempPath).Items.Count apiSleep(50) ENDDO ENDFOR CATCH TO loException this.ErrorLevelId = 12 RAISEEVENT(this, "OnShowErrorMessage", 12, "CreateExcelFile - Failed to add contents to Zip file"+ CR + loException.Message) SET STEP ON ERASE (lcZipFile) DO CASE CASE loException.ErrorNo = 1943 OTHERWISE SET STEP ON ENDCASE ENDTRY TRY apiMoveFile(lcZipFile, FORCEEXT(lcZipFile, "xlsx")) CATCH TO loException this.ErrorLevelId = 13 RAISEEVENT(this, "OnShowErrorMessage", 13, "CreateExcelFile - Rename failed"+ CR + loException.Message) SET STEP ON ENDTRY ENDIF RETURN True ENDPROC PROCEDURE createformatstyle && Creates a new format style definition LPARAMETERS tnWB IF PCOUNT() > 0 .AND. SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") lnId = this.GetNextId(tnWB, "xl_cellxfs") INSERT INTO xl_cellxfs (workbook, id, numFmtId, fontId, fillId, borderId, halign, valign, indent, wraptext, rotation) ; VALUES (tnWB, lnId, 0, 0, 0, 0, "", "", 0, 0, 0) RETURN lnId ELSE RETURN -1 ENDIF ENDPROC PROCEDURE createinlineformattext && Creates an in-line text formatted definition LPARAMETERS tnWB, tcCellText LOCAL loInline loInline = CREATEOBJECT("Empty") ADDPROPERTY(loInline, "Workbook", tnWB) ADDPROPERTY(loInline, "StringId", .NULL.) ADDPROPERTY(loInline, "StringValue", tcCellText) ADDPROPERTY(loInline, "Count", 0) ADDPROPERTY(loInline, "Characters[1]") loInline.Characters[1] = .NULL. RETURN loInline ENDPROC PROCEDURE createworkbook && Creates a new workbook object LPARAMETERS tcName LOCAL lcWBName, lcPath, lnWB IF PCOUNT() = 1 tlLoadDefaults = True ENDIF lcWBName = JUSTSTEM(tcName) lcPath = JUSTPATH(tcName) IF EMPTY(lcPath) lcPath = SYS(5) + SYS(2003) tcName = ADDBS(lcPath) + lcWBName + "." + JUSTEXT(tcName) ENDIF IF SEEK(PADR(UPPER(tcName), 240, "_"), "xl_workbooks", "fullname") lnWB = 0 ELSE INSERT INTO xl_workbooks (wbname, filepath, fullname) VALUES (lcWBName, lcPath, PADR(UPPER(tcName), 240, "_")) lnWB = xl_workbooks.workbook this.SetDefaultFont(lnWB, this.DefaultFont, this.DefaultFontSize) && Change recommended by Doug Hennig; 2017-06-12 this.SetDefaultBorder(lnWB, BORDER_STYLE_NONE) INSERT INTO xl_relationships (workbook, relid, reltype, target) VALUES (lnWB, 1, "styles", "styles.xml") INSERT INTO xl_relationships (workbook, relid, reltype, target) VALUES (lnWB, 2, "sharedStrings", "sharedStrings.xml") this.SetLastId(lnWB, 2, "xl_relationships") INSERT INTO xl_cellxfs (workbook, id, numFmtId, fontId, fillId, borderId, halign, valign, indent, wraptext) ; VALUES (lnWB, 0, 0, 0, 0, 0, "", "", 0, 0) INSERT INTO xl_fills (workbook, id, fgcolor, bgcolor, patttype, theme, tint, fgindexed, bgindexed) ; VALUES (lnWB, 0, 0, 0, FILL_STYLE_NONE, 0, 0, 0, 0) INSERT INTO xl_fills (workbook, id, fgcolor, bgcolor, patttype, theme, tint, fgindexed, bgindexed) ; VALUES (lnWB, 1, 0, 0, FILL_STYLE_GRAY125, 0, 0, 0, 0) ENDIF RETURN lnWB ENDPROC PROTECTED PROCEDURE createworkbookex && Internal method for creating a workbook LPARAMETERS tcName LOCAL lcWBName, lcPath, lnWB lcWBName = JUSTSTEM(tcName) lcPath = JUSTPATH(tcName) IF EMPTY(lcPath) lcPath = SYS(5) + SYS(2003) tcName = ADDBS(lcPath) + lcWBName + "." + JUSTEXT(tcName) ENDIF IF SEEK(PADR(UPPER(tcName), 240, "_"), "xl_workbooks", "fullname") lnWB = 0 ELSE INSERT INTO xl_workbooks (wbname, filepath, fullname) VALUES (lcWBName, lcPath, PADR(UPPER(tcName), 240, "_")) lnWB = xl_workbooks.workbook ENDIF RETURN lnWB ENDPROC PROTECTED PROCEDURE createworkingcursors && Creates the working cursors for worksheet definitions IF USED('xl_strings') RETURN ENDIF DO CASE CASE this.CodePage = 620 && Mazovia (Polish) MS-DOS CREATE CURSOR xl_strings CODEPAGE = 620 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 737 && Greek MS-DOS CREATE CURSOR xl_strings CODEPAGE = 737 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 852 && Eastern European MS-DOS CREATE CURSOR xl_strings CODEPAGE = 852 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 857 && Turkish MS-DOS CREATE CURSOR xl_strings CODEPAGE = 857 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 861 && Icelandic MS-DOS CREATE CURSOR xl_strings CODEPAGE = 861 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 865 && Nordic MS-DOS CREATE CURSOR xl_strings CODEPAGE = 865 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 866 && Russian MS-DOS CREATE CURSOR xl_strings CODEPAGE = 866 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 874 && Thai Windows CREATE CURSOR xl_strings CODEPAGE = 874 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 895 && Kamenicky (Czech) MS-DOS CREATE CURSOR xl_strings CODEPAGE = 895 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 932 && Japanese Windows CREATE CURSOR xl_strings CODEPAGE = 932 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 936 && Chinese Simplified (PRC, Singapore) Windows CREATE CURSOR xl_strings CODEPAGE = 936 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 949 &&Korean Windows CREATE CURSOR xl_strings CODEPAGE = 949 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 950 && Traditional Chinese (Hong Kong SAR, Taiwan) Windows CREATE CURSOR xl_strings CODEPAGE = 950 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1250 && Eastern European Windows CREATE CURSOR xl_strings CODEPAGE = 1250 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1251 && Russian Windows CREATE CURSOR xl_strings CODEPAGE = 1251 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1252 && Windows ANSI CREATE CURSOR xl_strings CODEPAGE = 1252 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1253 && Greek Windows CREATE CURSOR xl_strings CODEPAGE = 1253 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1254 && Turkish Windows CREATE CURSOR xl_strings CODEPAGE = 1254 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1255 && Hebrew Windows CREATE CURSOR xl_strings CODEPAGE = 1255 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) CASE this.CodePage = 1256 && Arabic Windows CREATE CURSOR xl_strings CODEPAGE = 1256 (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) OTHERWISE CREATE CURSOR xl_strings (id I, workbook I, checksum C(230), stringxml M, stringval M, presvspace L, formatted L) ENDCASE INDEX ON BINTOC(workbook)+BINTOC(id) TAG id FOR !DELETED() INDEX ON BINTOC(workbook)+PADL(id, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+checksum TAG stringndx INDEX ON workbook TAG workbook CREATE CURSOR xl_strformat (workbook I, id I, index I, stringxml M, stringval M, fbold L, fitalic L, fcolor I, fname C(100), fsize N(5,1), uline C(16), strkthr L, ; fvpos C(11), theme I, tint F(20,15), indexed I, presvspace L) INDEX ON BINTOC(workbook)+BINTOC(id)+PADL(index, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(id)+BINTOC(index) TAG id FOR !DELETED() CREATE CURSOR xl_workbooks (workbook I AUTOINC NEXTVALUE 1, wbname C(200), filepath C(200), fullname C(240)) INDEX ON BINTOC(workbook) TAG workbook INDEX ON UPPER(fullname) TAG fullname INDEX ON PADR(UPPER(ALLTRIM(wbname)), 200, "_") TAG wbname CREATE CURSOR xl_sheets (workbook I, sheet I, shname C(30), state I, mleft N(6,3), mright N(6,3), mtop N(6,3), mbot N(6,3), mheader N(6,3), ; mfooter N(6,3), shdeleted L, xsplit I, ysplit I, prnorient I, papersize I, paperwidth I, paperheight I, ; paperdimen C(2), scale I, fittowidth I, fittoheight I, tabcolorndx I, tabcolorrgb C(8)) INDEX ON sheet TAG sheet INDEX ON workbook TAG workbook INDEX ON BINTOC(workbook)+UPPER(ALLTRIM(shname)) TAG shname INDEX ON BINTOC(workbook)+BINTOC(sheet) TAG sheetndx FOR !DELETED() CREATE CURSOR xl_cells (workbook I, sheet I, cellrow I, cellcol I, cellvalue C(25), datatype C(1), cellformula M, stringid I, cellxfs I, numdec I, celldeleted L, validndx I) INDEX ON sheet TAG sheet INDEX ON cellrow TAG cellrow INDEX ON cellcol TAG cellcol INDEX ON workbook TAG workbook INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(cellrow)+BINTOC(cellcol) TAG reverse DESCENDING INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(cellrow)+BINTOC(cellcol) TAG cellindex CANDIDATE CREATE CURSOR xl_cellxfs (workbook I, id I, numFmtId I, fontId I, fillId I, borderId I, halign C(8), valign C(8), indent I, wraptext I, rotation I) INDEX ON BINTOC(workbook)+BINTOC(id) TAG id FOR !DELETED() INDEX ON BINTOC(workbook)+PADL(id, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(numFmtId)+BINTOC(fontId)+BINTOC(fillId)+BINTOC(borderId)+BINTOC(indent)+BINTOC(wraptext)+BINTOC(rotation)+ALLTRIM(halign)+ALLTRIM(valign) TAG cellxfs FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(fontId)+BINTOC(fillId)+BINTOC(borderId)+BINTOC(indent)+BINTOC(wraptext)+BINTOC(rotation)+ALLTRIM(halign)+ALLTRIM(valign) TAG cellformat FOR !DELETED() CREATE CURSOR xl_fonts (workbook I, id I, fname C(100), fsize N(5,1), fbold L, fitalic L, fcolor I, uline C(16), strkthr L, ; fvpos C(11), theme I, tint F(20,15), indexed I) INDEX ON BINTOC(workbook)+fname + STR(fsize, 5, 1) + TRANSFORM(fbold) + TRANSFORM(fitalic) + PADL(fcolor, 15) + uline + TRANSFORM(strkthr) + fvpos TAG cellformat INDEX ON BINTOC(workbook)+PADL(id, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(id) TAG id FOR !DELETED() CREATE CURSOR xl_fills (workbook I, id I, fgcolor I, bgcolor I, patttype C(25), theme I, tint F(20,15), fgindexed I, bgindexed I) INDEX ON BINTOC(workbook)+BINTOC(fgcolor)+BINTOC(bgcolor)+patttype TAG fillcolor INDEX ON BINTOC(workbook)+PADL(id, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(id) TAG id FOR !DELETED() CREATE CURSOR xl_borders (workbook I, id I, lstyle C(20), lcolor I, ltheme I, ltint I, lindexed I, rstyle C(20), rcolor I, rtheme I, rtint I, rindexed I, ; tstyle C(20), tcolor I, ttheme I, ttint I, tindexed I, bstyle C(20), bcolor I, btheme I, btint I, bindexed I, ; dstyle C(20), dcolor I, dtheme I, dtint I, dindexed I, diagdn I, diagup I, theme I, tint F(20,15)) INDEX ON BINTOC(workbook) + ALLTRIM(lstyle) + BINTOC(lcolor) + ALLTRIM(rstyle) + BINTOC(rcolor) + ALLTRIM(tstyle) + BINTOC(tcolor) + ALLTRIM(bstyle) + BINTOC(bcolor) + ; ALLTRIM(dstyle) + BINTOC(dcolor) + BINTOC(diagdn) + BINTOC(diagup) TAG cellborder INDEX ON BINTOC(workbook)+PADL(id, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(id) TAG id FOR !DELETED() CREATE CURSOR xl_mergecells (workbook I, sheet I, begrow I, begcol I, endrow I, endcol I) INDEX ON workbook TAG workbook INDEX ON sheet TAG sheet INDEX ON begrow TAG begrow INDEX ON begcol TAG begcol INDEX ON endrow TAG endrow INDEX ON endcol TAG endcol INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(begrow)+BINTOC(begcol) TAG mergecell FOR !DELETED() CREATE CURSOR xl_colwidths (workbook I, sheet I, column I, width N(16,9), bestfit L) INDEX ON sheet TAG sheet INDEX ON column TAG column INDEX ON workbook TAG workbook INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(column) TAG shcolumn FOR !DELETED() CREATE CURSOR xl_hdrfooterdefn (workbook I, sheet I, alignmargin L, difffirstpg L, diffoddeven L, scalewdoc L) INDEX ON workbook TAG workbook INDEX ON sheet TAG sheet INDEX ON BINTOC(workbook)+BINTOC(sheet) TAG wbsheet FOR !DELETED() CREATE CURSOR xl_hdrfootertext (workbook I, sheet I, page I, section I, text C(200), fontname C(50), fontsize I, fontstyle I, fontcolor I) INDEX ON workbook TAG workbook INDEX ON sheet TAG sheet INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(page)+BINTOC(section) TAG hdrfootr FOR !DELETED() CREATE CURSOR xl_rowheights (workbook I, sheet I, row I, height N(14,7)) INDEX ON workbook TAG workbook INDEX ON sheet TAG sheet INDEX ON row TAG row INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(row) TAG shrow FOR !DELETED() CREATE CURSOR xl_validation (workbook I, sheet I, validndx I AUTOINC NEXTVALUE 1, vtype I, vstyle I, voperator I, errmsg C(100), errtitle C(100), ; allowblank L, showinpmsg L, showerrmsg L, vprompt C(100), formula L, formula1 C(254), formula2 C(254)) INDEX ON BINTOC(validndx) TAG validndx FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(sheet) TAG wbshindex FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(validndx) TAG validindex FOR !DELETED() INDEX ON LEFT(formula1, 240) TAG formula1 FOR !DELETED() INDEX ON LEFT(formula2, 240) TAG formula2 FOR !DELETED() CREATE CURSOR xl_namerange (workbook I, rname C(50), scope I, comment C(254), sheet I, begrow I, begcol I, endrow I, endcol I) INDEX ON BINTOC(workbook)+rname TAG wbrname FOR !DELETED() CREATE CURSOR xl_numfmts (workbook I, id I, tempid I, formatxml M, formatcode M, applydec L) INDEX ON BINTOC(workbook)+PADL(id, 10, '0') TAG sortorder FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(id) TAG id FOR !DELETED() CREATE CURSOR xl_rows (workbook I, sheet I, row I, maxcol I) INDEX ON BINTOC(workbook)+BINTOC(sheet)+BINTOC(row) TAG id FOR !DELETED() CREATE CURSOR xl_ndxcolors (workbook I, indexid I, rgbcolor C(8)) INDEX ON BINTOC(workbook)+rgbcolor TAG rgbcolor FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(indexid) TAG indexid FOR !DELETED() CREATE CURSOR xl_mrucolors (workbook I, indexid I, rgbcolor C(8)) INDEX ON BINTOC(workbook)+rgbcolor TAG rgbcolor FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(indexid) TAG indexid FOR !DELETED() CREATE CURSOR xl_relationships (workbook I, sheet I, relid I, reltype C(20), target C(240)) INDEX ON BINTOC(workbook)+BINTOC(relid) TAG relid FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(sheet) TAG sheet FOR !DELETED() INDEX ON BINTOC(workbook)+reltype TAG reltype FOR !DELETED() CREATE CURSOR xl_extsheets (workbook I, extid I, relid I, sheetname C(30)) INDEX ON BINTOC(workbook)+BINTOC(extid) TAG extid FOR !DELETED() INDEX ON BINTOC(workbook)+BINTOC(extid)+BINTOC(relid) TAG relid FOR !DELETED() CREATE CURSOR xl_extcells (workbook I, extid I, cellrow I, cellcol I, cellvalue M) INDEX ON BINTOC(workbook)+BINTOC(extid) TAG extid FOR !DELETED() *INDEX ON BINTOC(workbook)+BINTOC(extid)+BINTOC(relid) TAG relid FOR !DELETED() ENDPROC PROTECTED PROCEDURE createworkingdirectories && Creates the working directories for the XML files LOCAL lcDir, loException lcDir = ADDBS(SYS(2023)) + SYS(2015) TRY MKDIR (lcDir) MKDIR (lcDir + "\_rels") MKDIR (lcDir + "\docProps") MKDIR (lcDir + "\xl") MKDIR (lcDir + "\xl\_rels") MKDIR (lcDir + "\xl\worksheets") CATCH TO loException lcDir = .NULL. ENDTRY RETURN ADDBS(lcDir) ENDPROC PROCEDURE debugcursorstofile && Debugging use for saving the internal cursors to a text file LPARAMETERS tcStemName LOCAL lnNumFlds, lcField, lcLineText, lnFld, lcFileName LOCAL ARRAY laFields[1, 18] SELECT xl_workbooks SET ORDER TO TAG workbook lnNumFlds = AFIELDS(laFields, "xl_workbooks") lcFileText = "Cursor: xl_workbooks" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_workbooks.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_workbooks.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_sheets SET ORDER TO TAG sheetndx lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_sheets") lcFileText = lcFileText + "Cursor: xl_sheets" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_sheets.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_sheets.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_cells SET ORDER TO TAG cellindex lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_cells") lcFileText = lcFileText + "Cursor: xl_cells" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_cells.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_cells.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_strings SET ORDER TO TAG stringid lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_strings") lcFileText = lcFileText + "Cursor: xl_strings" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_strings.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_strings.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_mergecells SET ORDER TO TAG mergecell lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_mergecells") lcFileText = lcFileText + "Cursor: xl_mergecells" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_mergecells.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_mergecells.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_colwidths SET ORDER TO TAG shcolumn lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_colwidths") lcFileText = lcFileText + "Cursor: xl_colwidths" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_colwidths.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_colwidths.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_fonts SET ORDER TO TAG id lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_fonts") lcFileText = lcFileText + "Cursor: xl_fonts" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_fonts.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_fonts.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_fills SET ORDER TO TAG id lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_fills") lcFileText = lcFileText + "Cursor: xl_fills" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_fills.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_fills.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_numfmts SET ORDER TO TAG id lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_numfmts") lcFileText = lcFileText + "Cursor: xl_numfmts" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_numfmts.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_numfmts.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_borders SET ORDER TO TAG id lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_borders") lcFileText = lcFileText + "Cursor: xl_borders" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_borders.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_borders.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_rowheights SET ORDER TO TAG shrow lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_rowheights") lcFileText = lcFileText + "Cursor: xl_rowheights" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_rowheights.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_rowheights.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_hdrfooterdefn SET ORDER TO TAG wbsheet lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_hdrfooterdefn") lcFileText = lcFileText + "Cursor: xl_hdrfooterdefn" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_hdrfooterdefn.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_hdrfooterdefn.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO SELECT xl_hdrfootertext SET ORDER TO TAG hdrfootr lcFileName = tcStemName + " " + ALIAS() + ".txt" LIST TO FILE (lcFileName) NOCONSOLE lnNumFlds = AFIELDS(laFields, "xl_hdrfootertext") lcFileText = lcFileText + "Cursor: xl_hdrfootertext" + CRLF SCAN lcField = LOWER(laFields[1, 1]) lcLineText = lcField + ": " + TRANSFORM(xl_hdrfootertext.&lcField) FOR lnFld=2 TO lnNumFlds lcField = LOWER(laFields[lnFld, 1]) lcLineText = lcLineText + "; " + lcField + ": " + TRANSFORM(xl_hdrfootertext.&lcField) ENDFOR lcFileText = lcFileText + lcLineText + CRLF ENDSCAN lcFileText = lcFileText + CRLF + CRLF + CRLF SET ORDER TO lcFileName = tcStemName + " Cursors.txt" STRTOFILE(lcFileText, lcFileName) ENDPROC PROCEDURE debugoutput && Limited functions for debugging LOCAL lnWb, lnSh lnWb = this.CreateWorkbook("ExcelDebug.xlsx") lnSh = this.AddSheet(lnWb, "Debug Output") this.SetCellValue(lnWb, lnSh, 1, 1, "Test string 1") this.SetCellValue(lnWb, lnSh, 2, 1, "Test string 2") this.SetCellValue(lnWb, lnSh, 3, 1, "Test string 3") this.SetCellValue(lnWb, lnSh, 4, 1, "Test string 4") this.SetCellValue(lnWb, lnSh, 5, 1, "Test string 5") this.SetCellValue(lnWb, lnSh, 8, 1, "This is a long Test string for word-wrapping to occur This is a long Test string for word-wrapping to occur") this.SetCellWordWrap(lnWb, lnSh, 8, 1, True) this.SetRowHeight(lnWb, lnSh, 8, 75) this.SetColumnWidth(lnWb, lnSh, 1, 25) this.SetCellValue(lnWb, lnSh, 10, 1, DATE(2015, 5, 6)) this.SetCellValue(lnWb, lnSh, 11, 1, DATETIME(2015, 5, 6, 6, 30, 30)) this.SetCellFont(lnWb, lnSh, 1, 1, "Arial", 14, True, , RGB(0,0,255)) this.SetCellFont(lnWb, lnSh, 2, 1, "Times New Roman", , , , RGB(0,0,255)) this.SetCellFont(lnWb, lnSh, 3, 1, "Consolas" , 14, True) this.SetCellFont(lnWb, lnSh, 4, 1, "Arial", 24, True, True, RGB(0,0,255)) this.SetCellFont(lnWb, lnSh, 5, 1, "Cooper Black" , 12, , , ) this.SetCellBorder(lnWb, lnSh, 2, 1, BORDER_TOP+BORDER_BOTTOM, BORDER_STYLE_THICK, RGB(100,150,200)) this.SetCellBorder(lnWb, lnSh, 5, 1, BORDER_LEFT+BORDER_RIGHT, BORDER_STYLE_DOUBLE, RGB(255,0,0)) this.SetCellFill(lnWb, lnSh, 1, 1, RGB(255,204,153)) this.SetCellFill(lnWb, lnSh, 3, 1, RGB(204,255,255)) this.SaveWorkbook(lnWb) ENDPROC PROCEDURE debug_assign LPARAMETERS tlDebug IF tlDebug SET DEBUGOUT TO "VFPXWorkbookXLSXDebug.txt" ENDIF this.Debug = tlDebug ENDPROC PROTECTED PROCEDURE declaredll && Declares the required support Win32 API DECLARE Sleep IN kernel32 AS apiSleep INTEGER tnTime DECLARE INTEGER DeleteFile IN kernel32 AS apiDeleteFile STRING lpFileName DECLARE INTEGER RemoveDirectory IN kernel32 AS apiRemoveDirectory STRING lpPathName DECLARE LONG MoveFile IN Win32API AS apiMoveFile STRING SourceFileName, STRING DestFileName DECLARE INTEGER ShellExecute IN Shell32 AS apiShellExecute LONG nhWnd, STRING lpAction, STRING lpFile, STRING lpParams, STRING lpDirectory, INTEGER nShowCmd ENDPROC PROCEDURE deleteallworkbooks && Deletes all workbooks LOCAL loException TRY this.DestroyWorkingCursors() this.CreateWorkingCursors() this.InitalizeIdValues() CATCH TO loException SET STEP ON ENDTRY ENDPROC PROCEDURE deletesheet && Deletes the sheet from the Workbook LPARAMETERS tnWB, txSheet LOCAL lnSheet, lxReturn lxReturn = False DO CASE CASE VARTYPE(txSheet) = "C" IF SEEK(BINTOC(tnWB)+UPPER(txSheet), "xl_sheets", "shname") .AND. SEEK(BINTOC(tnWB)+BINTOC(xl_sheets.sheet), "xl_relationships", "sheet") lnSheet = xl_sheets.sheet REPLACE xl_sheets.shdeleted WITH True IN xl_sheets DELETE IN xl_sheets DELETE IN xl_relationships lxReturn = True ENDIF CASE VARTYPE(txSheet) = "N" IF SEEK(BINTOC(tnWB)+BINTOC(txSheet), "xl_sheets", "sheetndx") .AND. SEEK(BINTOC(tnWB)+BINTOC(xl_sheets.sheet), "xl_relationships", "sheet") lnSheet = txSheet REPLACE xl_sheets.shdeleted WITH True IN xl_sheets DELETE IN xl_sheets DELETE IN xl_relationships lxReturn = True ENDIF ENDCASE IF lxReturn REPLACE xl_cells.celldeleted WITH True FOR workbook = tnWB .AND. sheet = lnSheet IN xl_cells DELETE FOR workbook = tnWB .AND. sheet = lnSheet IN xl_cells ENDIF RETURN lxReturn ENDPROC PROCEDURE deleteworkbook && Deletes the selected workbook LPARAMETERS tnWB LOCAL llSuccess, lnNdx TRY REPLACE xl_sheets.shdeleted WITH True FOR workbook = tnWB IN xl_sheets REPLACE xl_cells.celldeleted WITH True FOR workbook = tnWB IN xl_cells DELETE FOR workbook = tnWB IN xl_workbooks DELETE FOR workbook = tnWB IN xl_sheets DELETE FOR workbook = tnWB IN xl_cells DELETE FOR workbook = tnWB IN xl_strformat DELETE FOR workbook = tnWB IN xl_strings DELETE FOR workbook = tnWB IN xl_cellxfs DELETE FOR workbook = tnWB IN xl_fonts DELETE FOR workbook = tnWB IN xl_fills DELETE FOR workbook = tnWB IN xl_borders DELETE FOR workbook = tnWB IN xl_mergecells DELETE FOR workbook = tnWB IN xl_colwidths DELETE FOR workbook = tnWB IN xl_hdrfooterdefn DELETE FOR workbook = tnWB IN xl_hdrfootertext DELETE FOR workbook = tnWB IN xl_rowheights DELETE FOR workbook = tnWB IN xl_validation DELETE FOR workbook = tnWB IN xl_namerange DELETE FOR workbook = tnWB IN xl_numfmts DELETE FOR workbook = tnWB IN xl_rows DELETE FOR workbook = tnWB IN xl_ndxcolors DELETE FOR workbook = tnWB IN xl_mrucolors DELETE FOR workbook = tnWB IN xl_relationships DELETE FOR workbook = tnWB IN xl_extsheets DELETE FOR workbook = tnWB IN xl_extcells lnNdx = ASCAN(this.LastBorderId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastBorderId, lnNdx) lnNdx = ALEN(this.LastBorderId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastBorderId[lnNdx, 2] ELSE this.LastBorderId[1, 1] = 0 && Workbook Id this.LastBorderId[1, 2] = 0 && Last Border Id ENDIF ENDIF lnNdx = ASCAN(this.LastCellXfsId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastCellXfsId, lnNdx) lnNdx = ALEN(this.LastCellXfsId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastCellXfsId[lnNdx, 2] ELSE this.LastCellXfsId[1, 1] = 0 && Workbook Id this.LastCellXfsId[1, 2] = 0 && Last CellXfs Id ENDIF ENDIF lnNdx = ASCAN(this.LastFillId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastFillId, lnNdx) lnNdx = ALEN(this.LastFillId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastFillId[lnNdx, 2] ELSE this.LastFillId[1, 1] = 0 && Workbook Id this.LastFillId[1, 2] = 0 && Last Fill Id ENDIF ENDIF lnNdx = ASCAN(this.LastFontId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastFontId, lnNdx) lnNdx = ALEN(this.LastFontId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastFontId[lnNdx, 2] ELSE this.LastFontId[1, 1] = 0 && Workbook Id this.LastFontId[1, 2] = 0 && Last Font Id ENDIF ENDIF lnNdx = ASCAN(this.LastIndexColorId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastIndexColorId, lnNdx) lnNdx = ALEN(this.LastIndexColorId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastIndexColorId[lnNdx, 2] ELSE this.LastIndexColorId[1, 1] = 0 && Workbook Id this.LastIndexColorId[1, 2] = 0 && Last IndexColor Id ENDIF ENDIF lnNdx = ASCAN(this.LastMruColorId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastMruColorId, lnNdx) lnNdx = ALEN(this.LastMruColorId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastMruColorId[lnNdx, 2] ELSE this.LastMruColorId[1, 1] = 0 && Workbook Id this.LastMruColorId[1, 2] = 0 && Last mruColor Id ENDIF ENDIF lnNdx = ASCAN(this.LastNumFmtId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastNumFmtId, lnNdx) lnNdx = ALEN(this.LastNumFmtId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastNumFmtId[lnNdx, 2] ELSE this.LastNumFmtId[1, 1] = 0 && Workbook Id this.LastNumFmtId[1, 2] = 0 && Last NumFmt Id ENDIF ENDIF lnNdx = ASCAN(this.LastRelationId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastRelationId, lnNdx) lnNdx = ALEN(this.LastRelationId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastRelationId[lnNdx, 2] ELSE this.LastRelationId[1, 1] = 0 && Workbook Id this.LastRelationId[1, 2] = 0 && Last Relationship Id ENDIF ENDIF lnNdx = ASCAN(this.LastSheetId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastSheetId, lnNdx) lnNdx = ALEN(this.LastSheetId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastSheetId[lnNdx, 2] ELSE this.LastSheetId[1, 1] = 0 && Workbook Id this.LastSheetId[1, 2] = 0 && Last Sheet Id ENDIF ENDIF lnNdx = ASCAN(this.LastStringId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 ADEL(this.LastStringId, lnNdx) lnNdx = ALEN(this.LastStringId, 1) - 1 IF lnNdx > 0 DIMENSION this.LastStringId[lnNdx, 2] ELSE this.LastStringId[1, 1] = 0 && Workbook Id this.LastStringId[1, 2] = 0 && Last String Id ENDIF ENDIF llSuccess = True CATCH TO loException SET STEP ON llSuccess = False ENDTRY RETURN llSuccess ENDPROC PROCEDURE demo && Demo for the features of this class LOCAL lnWb, lnSh1, lnRow, lnCol, lnSh2, lnSh3, lnSh4, lnCnt, lnFormat, llBoolean, lcNamedRange LOCAL lnSh6, lnSh5, loInline, lnStyle1, lnStyle2, lnBorders, lcString lnWb = this.CreateWorkbook("ExcelTest.xlsx") IF lnWb = 0 RETURN False ENDIF lnSh1 = this.AddSheet(lnWb, "Test Sheet 1") IF lnSh1 = 0 RETURN False ENDIF this.FreezePanes(lnWb, lnSh1, 1, 2) llBoolean = True FOR lnRow=1 TO 10 FOR lnCol=1 TO 9 this.SetCellValue(lnWb, lnSh1, lnRow, lnCol, SYS(2015)) ENDFOR llBoolean = !llBoolean this.SetCellValue(lnWb, lnSh1, lnRow, 10, llBoolean) ENDFOR this.SetRowHeight(lnWb, lnSh1, 6, 25) *-* Example of cell styles lnStyle1 = this.CreateFormatStyle(lnWB) && Create the base style definition lnBorders = BORDER_LEFT + BORDER_RIGHT + BORDER_TOP + BORDER_BOTTOM this.AddStyleBorders(lnWB, lnStyle1, lnBorders, BORDER_STYLE_THIN, RGB(16,100,200)) this.AddStyleFont(lnWB, lnStyle1, "Times New Roman", 14, False, False, RGB(0,0,255)) this.SetCellStyleRange(lnWB, lnSh1, 2, 1, 2, 9, lnStyle1) lnStyle2 = this.CreateFormatStyle(lnWB) && Create the base style definition lnBorders = BORDER_BOTTOM this.AddStyleBorders(lnWB, lnStyle2, lnBorders, BORDER_STYLE_THICK, RGB(16,100,200)) this.AddStyleFont(lnWB, lnStyle2, "Arial", 16, True, False) this.SetCellStyleRange(lnWB, lnSh1, 4, 1, 4, 9, lnStyle2) *-* * Indentation examples [OLD WAY - DEPRICATED METHODS] *-* this.SetCellIndent(lnWb, lnSh1, 2, 6, 3) *-* this.SetCellIndent(lnWb, lnSh1, 4, 6, 3) *-* this.SetCellIndent(lnWb, lnSh1, 6, 6, 3) *-* this.SetCellIndent(lnWb, lnSh1, 8, 6, 3) *-* this.SetCellIndent(lnWb, lnSh1, 10, 6, 3) *-* *-* * tnWB, tnSheet, tnCellRow, tnCellCol, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos *-* this.SetCellFont(lnWb, lnSh1, 1, 1, "Arial", 14, True, True, RGB(0,0,255)) *-* this.SetCellFont(lnWb, lnSh1, 2, 1, "Times New Roman", , , , RGB(0,0,255)) *-* this.SetCellFont(lnWb, lnSh1, 3, 1, , 14, True) *-* this.SetCellFont(lnWb, lnSh1, 4, 1, "Arial", 14, True, True, RGB(0,0,255)) *-* this.SetCellFont(lnWb, lnSh1, 6, 1, , , , , , 'single') *-* this.SetCellFont(lnWb, lnSh1, 7, 1, , , , , , 'double') *-* this.SetCellFont(lnWb, lnSh1, 8, 1, , , , , , , True) *-* this.SetCellFont(lnWb, lnSh1, 9, 1, , , , , , , , "superscript") *-* *-* * New procedure each line is drawed with the same style and color *-* this.SetCellBorder(lnWb, lnSh1, 3, 4, 63, BORDER_STYLE_THIN, RGB(16,100,200)) *-* this.SetCellBorder(lnWb, lnSh1, 3, 6, 31, BORDER_STYLE_THICK, RGB(100,150,200)) *-* this.SetCellBorder(lnWb, lnSh1, 3, 8, 47, BORDER_STYLE_DOUBLE, RGB(200,150,100)) *-* this.SetCellBorder(lnWb, lnSh1, 3, 4, 8, BORDER_STYLE_THIN, RGB(16,100,200)) *-* *-* this.SetCellWordWrapRange(lnWb, lnSh1, 1, 1, 10, 9, True) *-* *-* * Old procedure - each line can have a different style or color *-* this.SetCellBorderEx(lnWb, lnSh1, 5, 2, 'thin',,'thin',,'thick',,'thick') *-* this.SetCellBorderEx(lnWb, lnSh1, 9, 2, ,,,,'double',255,'thick',RGB(255,0,255)) * Example of setting inline text formatting loInline = this.CreateInLineFormatText(lnWb, "This is an in-line formatted text string") loInline = this.AddInLineFontObject(loInline, 1, 4, "Arial Black", 16) loInline = this.AddInLineFontObject(loInline, 5, 15, "Times New Roman", 14, RGB(255,0,0), .T.) loInline = this.AddInLineFontObject(loInline, 20, 21, "Arial", 12) this.SetCellInLineFormatText(lnWb, lnSh1, 16, 1, loInline) * Rotated text this.SetCellValue(lnWb, lnSh1, 17, 1, "This text is rotated 45 degrees") this.SetCellTextRotation(lnWb, lnSh1, 17, 1, 45) this.SetCellValue(lnWb, lnSh1, 18, 1, "This text is rotated -45 degrees") this.SetCellTextRotation(lnWb, lnSh1, 18, 1, -45) * Similar text this.SetCellValue(lnWb, lnSh1, 15, 7, "This text is similar") this.SetCellValue(lnWb, lnSh1, 16, 7, "This text is similar to the one above but is longer length") *-* Very long text lcString = "Addtionally, there is a new method for reading an existing XLSX file into the working cursors and then supporting methods to extract the individual cell values and formatting. However, this XLSX read method is still in development " this.SetCellValue(lnWb, lnSh1, 22, 1, lcString) lcString = lcString + "and not yet ready for use. This is the method OpenXlsxWorkbook() - only use if you want to try it but the method will not necessarily read all the numeric" this.SetCellValue(lnWb, lnSh1, 23, 1, lcString) lcString = lcString + " or date values correctly at this point. I did not want to hold this release of VFPxWorkbookXlsx class for the completion of the reading of the XLSX file due to the other bug fixes." this.SetCellValue(lnWb, lnSh1, 24, 1, lcString) * Text with ASCII > 128 this.SetCellValue(lnWb, lnSh1, 19, 1, "This text that has ASCII chars > 128:" + CRLF + "Trademark symbol: " + CHR(174) + CRLF + "Copyright symbol: " + CHR(169)) * Column Width examples this.SetColumnWidth(lnWb, lnSh1, 1, 25) this.SetColumnWidth(lnWb, lnSh1, 2, 15) this.SetColumnWidth(lnWb, lnSh1, 3, 15) this.SetColumnWidth(lnWb, lnSh1, 4, 20) this.SetColumnWidth(lnWb, lnSh1, 5, 15) this.SetColumnWidth(lnWb, lnSh1, 6, 25) this.SetColumnWidth(lnWb, lnSh1, 9, 15) *Row inserted this.InsertRow(lnWb, lnSh1, 5, INSERT_AFTER) *Column inserted this.InsertColumn(lnWb, lnSh1, 5, INSERT_RIGHT) * Sheet setup examples this.SetPrintOrientation(lnWb, lnSh1, PORTRAIT_PRINT_ORIENTATION) this.SetPaperSize(lnWb, lnSh1, PAPERSIZE_LEGAL) this.SetSheetScale(lnWb, lnSh1, 50) ******************************************************************************* lnSh2 = this.AddSheet(lnWb, "Test Sheet 2") IF lnSh2 = 0 RETURN False ENDIF this.FreezePanes(lnWb, lnSh2, 1) this.SetCellValue(lnWb, lnSh2, 1, 1, "Column Header 1") this.SetCellValue(lnWb, lnSh2, 1, 2, "Column Header 2") this.SetCellValue(lnWb, lnSh2, 1, 3, "Column Header 3") this.SetCellValue(lnWb, lnSh2, 1, 4, "Column Header 4") this.SetCellValue(lnWb, lnSh2, 1, 5, "Column Header 5") this.SetCellFont(lnWb, lnSh2, 1, 1, "Arial", 14, True, False, RGB(255,255,255)) this.SetCellFill(lnWb, lnSh2, 1, 1, RGB(51,102,255)) this.CellFormatPainter(lnWb, lnSh2, 1, 1, 1, 2, 1, 5) this.SetColumnWidthRange(lnWb, lnSh2, 1, 5, 24) * Add integer values to cells FOR lnRow=2 TO 6 FOR lnCol=1 TO 5 this.SetCellValue(lnWb, lnSh2, lnRow, lnCol, lnRow*lnCol) ENDFOR ENDFOR * Add SUM() formula to columns FOR lnCol=1 TO 5 lcColumn = this.ColumnIndexToAscii(lnCol) this.SetCellFormula(lnWb, lnSh2, 7, lnCol, "=SUM(" + lcColumn + "2:" + lcColumn + "6)") ENDFOR * Add floating point values to cells FOR lnRow=10 TO 15 FOR lnCol=3 TO 5 this.SetCellValue(lnWb, lnSh2, lnRow, lnCol, lnRow*1.25) ENDFOR ENDFOR * Add AVERAGE(), MAX(), & MIN() formula to columns this.SetCellFormula(lnWb, lnSh2, 16, 3, "=AVERAGE(C10:C15)") this.SetCellFormula(lnWb, lnSh2, 16, 4, "=MAX(D10:D15)") this.SetCellFormula(lnWb, lnSh2, 16, 5, "=MIN(E10:E15)") this.SetCellValue(lnWb, lnSh2, 16, 1, "This row contains calculated formulas -->") * Merge some cells this.MergeCells(lnWb, lnSh2, 2, 8, 2, 10) this.MergeCells(lnWb, lnSh2, 3, 8, 3, 10) this.MergeCells(lnWb, lnSh2, 5, 8, 10, 10) this.SetCellValue(lnWb, lnSh2, 2, 8, "Merged H2:J2") this.SetCellValue(lnWb, lnSh2, 3, 8, "Merged H3:J3") this.SetCellValue(lnWb, lnSh2, 5, 8, "Merged H5:J10") this.SetCustomPaperSize(lnWb, lnSh2, 841, 1189, "mm") this.SetHeaderFooterSetup(lnWb, lnSh2, False, True, False, False) this.SetHeaderFooterText(lnWb, lnSh2, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_HDR_CENTER, "This is First Page", "Arial", 16, HEADERFOOTER_FONT_STYLE_BOLD, RGB(255,0,0)) this.SetHeaderFooterText(lnWb, lnSh2, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_HDR_CENTER, "These are Additional Pages", "Arial", 10, HEADERFOOTER_FONT_STYLE_BOLD, RGB(0,128,0)) this.SetHeaderFooterText(lnWb, lnSh2, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_FTR_CENTER, "Page &P of &N", "Arial", 16, HEADERFOOTER_FONT_STYLE_BOLD) ******************************************************************************* lnSh3 = this.AddSheet(lnWb, "Number Formats") IF lnSh3 = 0 RETURN False ENDIF lnFormat = this.AddNumericFormat(lnWb, '[Green]"$"#,##0.00;[Red]"$"#,##0.00') *lnFormat = this.AddCustomNumericFormat(lnWb, '[Green]"$"#,##0.00', '[Red]"$"#,##0.00') this.SetCellValue(lnWb, lnSh3, 1, 1, 56.558) this.SetCellValue(lnWb, lnSh3, 1, 2, "Custom defined format: " + this.GetCustomNumericFormat(lnWb, lnFormat)) this.SetCellNumberFormat(lnWb, lnSh3, 1, 1, lnFormat) this.SetColumnWidth(lnWb, lnSh3, 1, 18) this.SetColumnWidth(lnWb, lnSh3, 2, 60) this.SetCellValue(lnWb, lnSh3, 3, 1, 14) this.SetCellValue(lnWb, lnSh3, 3, 2, "Integer format") this.SetCellNumberFormat(lnWb, lnSh3, 3, 1, CELL_FORMAT_INTEGER) this.SetCellValue(lnWb, lnSh3, 4, 1, 13355.2) this.SetCellValue(lnWb, lnSh3, 4, 2, "Float format") this.SetCellNumberFormat(lnWb, lnSh3, 4, 1, CELL_FORMAT_FLOAT) this.SetCellValue(lnWb, lnSh3, 5, 1, 16898) this.SetCellValue(lnWb, lnSh3, 5, 2, "Integer format, comma separated") this.SetCellNumberFormat(lnWb, lnSh3, 5, 1, CELL_FORMAT_COMMA_INTEGER) this.SetCellValue(lnWb, lnSh3, 6, 1, 13355.20) this.SetCellValue(lnWb, lnSh3, 6, 2, "Float format, comma separated") this.SetCellNumberFormat(lnWb, lnSh3, 6 , 1, CELL_FORMAT_COMMA_FLOAT) this.SetCellValue(lnWb, lnSh3, 7, 1, -13355.20) this.SetCellValue(lnWb, lnSh3, 7, 2, "Currency format, negative in parenthesis") this.SetCellNumberFormat(lnWb, lnSh3, 7, 1, CELL_FORMAT_CURRENCY_PAREN) this.SetCellValue(lnWb, lnSh3, 8, 1, -13355.20) this.SetCellValue(lnWb, lnSh3, 8, 2, "Currency format, negative red in parenthesis") this.SetCellNumberFormat(lnWb, lnSh3, 8, 1, CELL_FORMAT_CURRENCY_RED_PAREN) this.SetCellValue(lnWb, lnSh3, 10, 1, 0.55) this.SetCellValue(lnWb, lnSh3, 10, 2, "Percent format, integer") this.SetCellNumberFormat(lnWb, lnSh3, 10, 1, CELL_FORMAT_PERCENT_INTEGER) this.SetCellValue(lnWb, lnSh3, 11, 1, 0.5534) this.SetCellValue(lnWb, lnSh3, 11, 2, "Percent format, float") this.SetCellNumberFormat(lnWb, lnSh3, 11, 1, CELL_FORMAT_PERCENT_FLOAT) this.SetCellValue(lnWb, lnSh3, 13, 1, 456800000.00) this.SetCellValue(lnWb, lnSh3, 13, 2, "Exponential format") this.SetCellNumberFormat(lnWb, lnSh3, 13, 1, CELL_FORMAT_EXPONENT) this.SetCellValue(lnWb, lnSh3, 15, 1, 0.25) this.SetCellValue(lnWb, lnSh3, 15, 2, "Fraction format, single place") this.SetCellNumberFormat(lnWb, lnSh3, 15, 1, CELL_FORMAT_FRACTION_1) this.SetCellValue(lnWb, lnSh3, 16, 1, 0.3125) this.SetCellValue(lnWb, lnSh3, 16, 2, "Fraction format, 2 places") this.SetCellNumberFormat(lnWb, lnSh3, 16, 1, CELL_FORMAT_FRACTION_2) this.SetCellValue(lnWb, lnSh3, 18, 1, DATE()) this.SetCellValue(lnWb, lnSh3, 18, 2, "Default date format") this.SetCellNumberFormat(lnWb, lnSh3, 18, 1, CELL_FORMAT_DATE_DMMMYY) this.SetCellValue(lnWb, lnSh3, 19, 1, DATE()) this.SetCellValue(lnWb, lnSh3, 19, 2, "Date format, d-mmm-yy") this.SetCellNumberFormat(lnWb, lnSh3, 19, 1, CELL_FORMAT_DATE_DMMMYY) this.SetCellValue(lnWb, lnSh3, 20, 1, DATE()) this.SetCellValue(lnWb, lnSh3, 20, 2, "Date format, d-mmm") this.SetCellNumberFormat(lnWb, lnSh3, 20, 1, CELL_FORMAT_DATE_DMMM) this.SetCellValue(lnWb, lnSh3, 21, 1, DATE()) this.SetCellValue(lnWb, lnSh3, 21, 2, "Date format, mmm-yy") this.SetCellNumberFormat(lnWb, lnSh3, 21, 1, CELL_FORMAT_DATE_MMMYY) this.SetCellValue(lnWb, lnSh3, 23, 1, 0.35733796296296294) this.SetCellValue(lnWb, lnSh3, 23, 2, "Time format, h:mm AM/PM") this.SetCellNumberFormat(lnWb, lnSh3, 23, 1, CELL_FORMAT_TIME_HMMAMPM) this.SetCellValue(lnWb, lnSh3, 24, 1, 0.35733796296296294) this.SetCellValue(lnWb, lnSh3, 24, 2, "Time format, h:mm:ss AM/PM") this.SetCellNumberFormat(lnWb, lnSh3, 24, 1, CELL_FORMAT_TIME_HMMSSAMPM) this.SetCellValue(lnWb, lnSh3, 25, 1, 0.35733796296296294) this.SetCellValue(lnWb, lnSh3, 25, 2, "Time format, h:mm") this.SetCellNumberFormat(lnWb, lnSh3, 25, 1, CELL_FORMAT_TIME_HMM) this.SetCellValue(lnWb, lnSh3, 26, 1, 0.35733796296296294) this.SetCellValue(lnWb, lnSh3, 26, 2, "Time format, h:mm:ss") this.SetCellNumberFormat(lnWb, lnSh3, 26, 1, CELL_FORMAT_TIME_HMMSS) this.SetCellValue(lnWb, lnSh3, 28, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 28, 2, "Date-Time format, m/d/yy h:mm") this.SetCellNumberFormat(lnWb, lnSh3, 28, 1, CELL_FORMAT_DATETIME_MDYYHMM) this.SetCellValue(lnWb, lnSh3, 29, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 29, 2, "Date-Time format, [$-409]dd/mmm/yyyy\ h:mm\ AM/PM;@") this.SetCellNumberFormat(lnWb, lnSh3, 29, 1, CELL_FORMAT_DATETIME_DDMMMYYYY_TTAM) this.SetCellValue(lnWb, lnSh3, 30, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 30, 2, "Date-Time format, dd/mmm/yyyy\ h:mm;@") this.SetCellNumberFormat(lnWb, lnSh3, 30, 1, CELL_FORMAT_DATETIME_DDMMMYYYY_TT24) this.SetCellValue(lnWb, lnSh3, 31, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 31, 2, "Date-Time format, [$-409]mmm\ d\,\ yyyy\ h:mm\ AM/PM;@") this.SetCellNumberFormat(lnWb, lnSh3, 31, 1, CELL_FORMAT_DATETIME_MMMDDYYYY_TTAM) this.SetCellValue(lnWb, lnSh3, 32, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 32, 2, "Date-Time format, [$-409]mmm\ d\,\ yyyy\ h:mm;@") this.SetCellNumberFormat(lnWb, lnSh3, 32, 1, CELL_FORMAT_DATETIME_MMMDDYYYY_TT24) this.SetCellValue(lnWb, lnSh3, 33, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 33, 2, "Date-Time format, m/d/yy\ h:mm\ AM/PM;@") this.SetCellNumberFormat(lnWb, lnSh3, 33, 1, CELL_FORMAT_DATETIME_MDYY_TTAM) this.SetCellValue(lnWb, lnSh3, 34, 1, DATETIME()) this.SetCellValue(lnWb, lnSh3, 34, 2, "Date-Time format, m/d/yy\ h:mm;@") this.SetCellNumberFormat(lnWb, lnSh3, 34, 1, CELL_FORMAT_DATETIME_MDYY_TT24) this.SetCellValue(lnWb, lnSh3, 36, 1, -89235) this.SetCellValue(lnWb, lnSh3, 36, 2, "Numeric format, #,##0;(#,##0)") this.SetCellNumberFormat(lnWb, lnSh3, 36, 1, CELL_FORMAT_COMMA_INTEGER_PAREN) this.SetCellValue(lnWb, lnSh3, 37, 1, -12457) this.SetCellValue(lnWb, lnSh3, 37, 2, "Numeric format, #,##0;[Red](#,##0)") this.SetCellNumberFormat(lnWb, lnSh3, 37, 1, CELL_FORMAT_COMMA_INTEGER_RED_PAREN) this.SetCellValue(lnWb, lnSh3, 38, 1, -1245789.22) this.SetCellValue(lnWb, lnSh3, 38, 2, "Numeric format, #,##0.00;(#,##0.00)") this.SetCellNumberFormat(lnWb, lnSh3, 38, 1, CELL_FORMAT_COMMA_FLOAT_PAREN) this.SetCellValue(lnWb, lnSh3, 39, 1, -125896.33) this.SetCellValue(lnWb, lnSh3, 39, 2, "Numeric format, #,##0.00;[Red](#,##0.00)") this.SetCellNumberFormat(lnWb, lnSh3, 39, 1, CELL_FORMAT_COMMA_FLOAT_RED_PAREN) this.SetCellValue(lnWb, lnSh3, 41, 1, 6.25E-2) this.SetCellValue(lnWb, lnSh3, 41, 2, "Time format") this.SetCellNumberFormat(lnWb, lnSh3, 41, 1, CELL_FORMAT_TIME_MMSS) this.SetCellValue(lnWb, lnSh3, 42, 1, 0.35733796296296294) this.SetCellValue(lnWb, lnSh3, 42, 2, "Time format, [h]:mm:ss") this.SetCellNumberFormat(lnWb, lnSh3, 42, 1, CELL_FORMAT_TIME_H_MMSS) this.SetCellValue(lnWb, lnSh3, 44, 1, -45.55) this.SetCellValue(lnWb, lnSh3, 44, 2, "CELL_FORMAT_CURRENCY_RED") this.SetCellNumberFormat(lnWb, lnSh3, 44, 1, CELL_FORMAT_CURRENCY_RED) this.SetCellValue(lnWb, lnSh3, 45, 1, -45.55) this.SetCellValue(lnWb, lnSh3, 45, 2, "CELL_FORMAT_ACC_CURR_POUNDS") this.SetCellNumberFormat(lnWb, lnSh3, 45, 1, CELL_FORMAT_ACC_CURR_POUNDS) this.SetCellValue(lnWb, lnSh3, 46, 1, -45.55) this.SetCellValue(lnWb, lnSh3, 46, 2, "CELL_FORMAT_ACC_CURR_EURO") this.SetCellNumberFormat(lnWb, lnSh3, 46, 1, CELL_FORMAT_ACC_CURR_EURO) this.SetCellValue(lnWb, lnSh3, 47, 1, -45.55) this.SetCellValue(lnWb, lnSh3, 47, 2, "CELL_FORMAT_CURR_EURO_RED") this.SetCellNumberFormat(lnWb, lnSh3, 47, 1, CELL_FORMAT_CURR_EURO_RED) this.SetCellValue(lnWb, lnSh3, 48, 1, -45.55) this.SetCellValue(lnWb, lnSh3, 48, 2, "CELL_FORMAT_CURR_POUNDS_RED") this.SetCellNumberFormat(lnWb, lnSh3, 48, 1, CELL_FORMAT_CURR_POUNDS_RED) this.SetPrintOrientation(lnWb, lnSh3, LANDSCAPE_PRINT_ORIENTATION) *-* this.SetPrintFitToHeight(lnWb, lnSh3, 2) ******************************************************************************* lnSh4 = this.AddSheet(lnWb, "Color Sheet") IF lnSh4 = 0 RETURN False ENDIF this.SetCellValue(lnWb, lnSh4, 1, 1, "RGB(51,102,255)") this.SetCellFill(lnWb, lnSh4, 1, 1, RGB(51,102,255)) this.SetCellValue(lnWb, lnSh4, 1, 2, "RGB(255,0,0)") this.SetCellFill(lnWb, lnSh4, 1, 2, RGB(255,0,0)) this.SetCellAlignmentRange(lnWb, lnSh4, 1, 1, 1, 2, CELL_HORIZ_ALIGN_CENTER, CELL_VERT_ALIGN_CENTER) this.SetColumnWidthRange(lnWb, lnSh4, 1, 2, 18) this.SetRowHeight(lnWb, lnSh4, 1, 60) ******************************************************************************* lnSh5 = this.AddSheet(lnWb, "Blank Sheet") ******************************************************************************* lnSh6 = this.AddSheet(lnWb, "List Values", HIDDEN_SHEET_STATE) IF lnSh6 = 0 RETURN False ENDIF this.SetCellValidation(lnWb, lnSh1, 13, 1, LIST_VALID_TYPE, , , , , , , , , "Yes,No,Maybe") this.SetCellValue(lnWb, lnSh1, 13, 2, "The cell to the left has a droplist validation") this.SetCellValue(lnWb, lnSh6, 1, 1, "Named Value List") this.SetCellValue(lnWb, lnSh6, 2, 1, "Named Value 1") this.SetCellValue(lnWb, lnSh6, 3, 1, "Named Value 2") this.SetCellValue(lnWb, lnSh6, 4, 1, "Named Value 3") this.SetCellValue(lnWb, lnSh6, 5, 1, "Named Value 4") this.SetCellValue(lnWb, lnSh6, 6, 1, "Named Value 5") this.SetCellValue(lnWb, lnSh6, 7, 1, "Named Value 6") lcNamedRange = this.AddNamedRange(lnWb, lnSh6, "Named Range", SCOPE_WB_NAMED_RANGE, "This is a comment", 2, 1, 7, 1) this.SetCellValidation(lnWb, lnSh1, 14, 1, LIST_VALID_TYPE, , , , , , , , , "=" + lcNamedRange) this.SetCellValue(lnWb, lnSh1, 14, 2, "The cell to the left has a droplist validation based on a Named Range (stored in Hidden Sheet6)") this.InsertCell(lnWb, lnSh1, 9, 9, INSERT_RIGHT) this.InsertCell(lnWb, lnSh1, 11, 9, INSERT_BEFORE) *-* For testing sheet saving only *this.DeleteSheet(lnWb, lnSh2) this.SaveWorkbook(lnWb) IF this.Debug this.DebugCursorsToFile("ExcelTest") ENDIF ENDPROC PROTECTED PROCEDURE derivesheetname && Derives the sheet name LPARAMETERS txWB DO CASE CASE VARTYPE(txWB) = "C" lcSheetName = JUSTSTEM(txWB) CASE VARTYPE(txWB) = "N" lcSheetName = JUSTSTEM(this.GetWorkbookFileName(txWB)) OTHERWISE RETURN "" ENDCASE RETURN lcSheetName ENDPROC PROTECTED PROCEDURE Destroy SET DEBUGOUT TO this.DestroyWorkingCursors() this.OnDestroy() ENDPROC PROTECTED PROCEDURE destroyworkingcursors && Destroys the working cursors TRY USE IN SELECT('xl_strings') USE IN SELECT('xl_workbooks') USE IN SELECT('xl_sheets') USE IN SELECT('xl_cells') USE IN SELECT('xl_fonts') USE IN SELECT('xl_fills') USE IN SELECT('xl_borders') USE IN SELECT('xl_mergecells') USE IN SELECT('xl_colwidths') USE IN SELECT('xl_hdrfooterdefn') USE IN SELECT('xl_hdrfootertext') USE IN SELECT('xl_rowheights') USE IN SELECT('xl_numfmts') USE IN SELECT('xl_namerange') USE IN SELECT('xl_validation') USE IN SELECT('xl_strformat') USE IN SELECT('xl_cellxfs') USE IN SELECT('xl_rows') USE IN SELECT('xl_ndxcolors') USE IN SELECT('xl_mrucolors') USE IN SELECT('xl_relationships') USE IN SELECT('xl_extsheets') USE IN SELECT('xl_extcells') CATCH TO loException ENDTRY ENDPROC PROTECTED PROCEDURE documentation && Documentation of the methods and properties for this class *-* *-* Written by: Vilhelm Praisach *-* Gregory Green *-* *-* Release History: *-* *-* May 11, 2015 Initial release. *-* May 12, 2015 Added new methods: SetCellFormatRange, SetCellBorderRange, SaveGridToWorkbook *-* Added new properties: Title, Subject, CompanyName *-* Added check in SetCellValue that if a value is being set in a merged cell range then the value is set in the upper *-* left cell of the merged range *-* Corrected sheet references when writing the sheet XML *-* May 27, 2015 Added new methods: ConvertPixelsToExcelUnits, GetWorkbook, GetWorkbookSheets, DeleteWorkbook, DeleteAllWorkbooks, *-* SetCellAlignment, SetCellNumberDecimals, SetCellNumberFormat, SetCellNumberFormatRange, *-* SetColumnWidthRange, SetRowHeight, SetRowHeightRange, SetCellWordWrap *-* Renamed method RemoveSheet to DeleteSheet *-* Corrected string to XML conversion (was performing a double conversion of the string) *-* Corrected issue of generated XLSX file being deleted; increase of Sleep() time for file rename *-* June 1, 2015 Corrected bug in merge cell and cell value assignment (after a merge cell was performed any subsequent sheets *-* added that had cells in the same merge range with value assignments was not having the values set correctly) *-* Changed property name ExcelXlsxVersion to ExcelXlsxRelease; this property will give the Release number (integer) *-* of this class *-* June 5, 2015 Added to set the default selected table/cursor (value retuned by ALIAS() function) when the default table/cursor *-* is changed in a method *-* Added new method: SaveTableToWorkbook *-* June 8, 2015 No new features. Code was optimized for better performance. *-* *-* The first optimization I changed the SetCellValue() code to now always attempt to INSERT first. I added the CANDIDATE *-* clause to the primary INDEX so that if a cell is already entered, the INSERT command will fail in a TRY-CATCH block *-* (duplicate KEY); in the CATCH portion I do an update to the cell value. This reduced the time to assign the values *-* significantly. I had been doing a SEEK() for the cell and updating if found otherwise doing an INSERT *-* *-* The second optimization was how I was assigning a string index value. The original code did a SELECT-SQL WITH a MAX() *-* for the last used index value IN the workbook (strings are universal TO a workbook); I changed to a property value *-* (array indexed by the workbook number) and then just increment this value as it is used. Great amount of savings here too. *-* *-* The LAST optimization was in how the Sheet.xml were being written. I now just do a SCAN across the cells and add to the *-* XML. I was doing several SQL calls to first get the rows and then SQL calls TO the columns for each row. Again not as *-* efficient as just SCAN-ENDSCAN on the cells cursor table. Had to build in logic to populate rows that did not have a *-* cell value assigned but had row height assigned. The SQL coding was easier for this but at a great cost in time. *-* June 9, 2015 No new features. Bug fix for a nasty crash of Excel when the print or print-preview is selected. Congratulations to *-* Vilhelm for finding this bug. *-* July 1, 2015 Corrected return value for AddNumericFormat. *-* Changed the parameters on AddNumericFormat(); now just pass the numeric format *-* *-* Oct 29, 2015 Added new functions for opening an existing workbook (xlsx). Added sheet print formatting methods. *-* *-************************************************************************************************************************************ ENDPROC PROCEDURE freezepanes && Freezes the panes of the sheet LPARAMETERS tnWB, tnSheet, tnTopRowCount, tnSideColCount LOCAL lxReturn DO CASE CASE PCOUNT() < 3 RETURN False CASE PCOUNT() = 3 tnSideColCount = 0 ENDCASE IF VARTYPE(tnTopRowCount) != 'N' tnTopRowCount = 0 ENDIF IF VARTYPE(tnSideColCount) != 'N' tnSideColCount = 0 ENDIF IF this.GetSheetRecord(tnWB, tnSheet) REPLACE xl_sheets.xsplit WITH tnSideColCount, ; xl_sheets.ysplit WITH tnTopRowCount IN xl_sheets lxReturn = True ELSE lxReturn = False ENDIF RETURN lxReturn ENDPROC PROTECTED PROCEDURE getalphanumericsplit && Returns the position of the alpha and numeric split LPARAMETERS tcText LOCAL lnChr FOR lnChr=1 TO LEN(tcText) IF ISDIGIT(SUBSTR(tcText, lnChr, 1)) RETURN lnChr ENDIF ENDFOR RETURN 0 ENDPROC PROTECTED PROCEDURE getbordersrecord && Gets the border record; returns True if found, or False in not found LPARAMETERS tnWB, tcLStyle, tnLColor, tcRStyle, tnRColor, tcTStyle, tnTColor, tcBStyle, tnBColor, tcDStyle, tnDColor, tnDiagDn, tnDiagUp RETURN SEEK(BINTOC(tnWB) + tcLStyle + BINTOC(tnLColor) + tcRStyle + BINTOC(tnRColor) + tcTStyle + BINTOC(tnTColor) + tcBStyle + BINTOC(tnBColor) + ; tcDStyle + BINTOC(tnDColor) + BINTOC(tnDiagDn) + BINTOC(tnDiagUp), "xl_borders", "cellborder") ENDPROC PROCEDURE getcellalignment && Returns the cell alignment LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loAlignInfo IF PCOUNT() < 4 RETURN .NULL. ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) loAlignInfo = CREATEOBJECT("Empty") ADDPROPERTY(loAlignInfo, "HorzAlign", xl_cellxfs.halign) ADDPROPERTY(loAlignInfo, "VertAlign", xl_cellxfs.valign) ELSE loAlignInfo = .NULL. ENDIF RETURN loAlignInfo ENDPROC PROCEDURE getcellborders && Returns the cell border info LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loBdrInfo IF PCOUNT() < 4 RETURN .NULL. ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) .AND. this.GetCursorRecord("xl_borders", tnWB, xl_cellxfs.borderId) loBdrInfo = CREATEOBJECT("Empty") ADDPROPERTY(loBdrInfo, "LeftStyle", xl_borders.lstyle) ADDPROPERTY(loBdrInfo, "LeftColor", xl_borders.lcolor) ADDPROPERTY(loBdrInfo, "LeftTheme", xl_borders.ltheme) ADDPROPERTY(loBdrInfo, "LeftTint", xl_borders.ltint) ADDPROPERTY(loBdrInfo, "LeftIndex", xl_borders.lindexed) ADDPROPERTY(loBdrInfo, "RightStyle", xl_borders.rstyle) ADDPROPERTY(loBdrInfo, "RightColor", xl_borders.rcolor) ADDPROPERTY(loBdrInfo, "RightTheme", xl_borders.rtheme) ADDPROPERTY(loBdrInfo, "RightTint", xl_borders.rtint) ADDPROPERTY(loBdrInfo, "RightIndex", xl_borders.rindexed) ADDPROPERTY(loBdrInfo, "TopStyle", xl_borders.tstyle) ADDPROPERTY(loBdrInfo, "TopColor", xl_borders.tcolor) ADDPROPERTY(loBdrInfo, "TopTheme", xl_borders.ttheme) ADDPROPERTY(loBdrInfo, "TopTint", xl_borders.ttint) ADDPROPERTY(loBdrInfo, "TopIndex", xl_borders.tindexed) ADDPROPERTY(loBdrInfo, "BotStyle", xl_borders.bstyle) ADDPROPERTY(loBdrInfo, "BotColor", xl_borders.bcolor) ADDPROPERTY(loBdrInfo, "BotTheme", xl_borders.btheme) ADDPROPERTY(loBdrInfo, "BotTint", xl_borders.btint) ADDPROPERTY(loBdrInfo, "BotIndex", xl_borders.bindexed) ADDPROPERTY(loBdrInfo, "DiagStyle", xl_borders.dstyle) ADDPROPERTY(loBdrInfo, "DiagColor", xl_borders.dcolor) ADDPROPERTY(loBdrInfo, "DiagTheme", xl_borders.dtheme) ADDPROPERTY(loBdrInfo, "DiagTint", xl_borders.dtint) ADDPROPERTY(loBdrInfo, "DiagIndex", xl_borders.dindexed) ADDPROPERTY(loBdrInfo, "DiagDn", xl_borders.diagdn) ADDPROPERTY(loBdrInfo, "DiagUp", xl_borders.diagup) ELSE loBdrInfo = .NULL. ENDIF RETURN loBdrInfo ENDPROC PROCEDURE getcelldatatype && Returns the data type for the selected cell LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lxReturn IF PCOUNT() < 4 RETURN .NULL. ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) lxReturn = xl_cells.datatype ELSE lxReturn = .NULL. ENDIF RETURN lxReturn ENDPROC PROCEDURE getcellfill && Returns the fill info for the cell LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loFillInfo IF PCOUNT() < 4 RETURN .NULL. ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) .AND. this.GetCursorRecord("xl_fills", tnWB, xl_cellxfs.fillid) loFillInfo = CREATEOBJECT("Empty") ADDPROPERTY(loFillInfo, "FgColor", xl_fills.fgcolor) ADDPROPERTY(loFillInfo, "BgColor", xl_fills.bgcolor) ADDPROPERTY(loFillInfo, "PatType", xl_fills.patttype) ADDPROPERTY(loFillInfo, "Theme", xl_fills.theme) ADDPROPERTY(loFillInfo, "Tint", xl_fills.tint) ADDPROPERTY(loFillInfo, "FgIndexed", xl_fills.fgindexed) ADDPROPERTY(loFillInfo, "BgIndexed", xl_fills.bgindexed) ELSE loFillInfo = .NULL. ENDIF RETURN loFillInfo ENDPROC PROCEDURE getcellfont && Returns the cell font settings LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loFontInfo IF PCOUNT() < 4 RETURN .NULL. ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) .AND. this.GetCursorRecord("xl_fonts", tnWB, xl_cellxfs.fontid) loFontInfo = CREATEOBJECT("Empty") ADDPROPERTY(loFontInfo, "FontName", ALLTRIM(xl_fonts.fname)) ADDPROPERTY(loFontInfo, "FontSize", xl_fonts.fsize) ADDPROPERTY(loFontInfo, "FontBold", xl_fonts.fbold) ADDPROPERTY(loFontInfo, "FontItalic", xl_fonts.fitalic) ADDPROPERTY(loFontInfo, "ForeColor", xl_fonts.fcolor) ADDPROPERTY(loFontInfo, "FontUnderline", ALLTRIM(xl_fonts.uline)) ADDPROPERTY(loFontInfo, "FontStrikeThr", xl_fonts.strkthr) ADDPROPERTY(loFontInfo, "FontVerticalPos", ALLTRIM(xl_fonts.fvpos)) ELSE loFontInfo = .NULL. ENDIF RETURN loFontInfo ENDPROC PROCEDURE getcellformula && Returns the cell formula expression LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lcFormula IF PCOUNT() < 4 RETURN .NULL. ENDIF lcFormula = .NULL. IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) lcFormula = ALLTRIM(xl_cells.cellformula) ENDIF RETURN lcFormula ENDPROC PROTECTED PROCEDURE getcellformulafromxml && Gets the cell formula from the XML node LPARAMETERS tcFormula, tnCellCol LOCAL lcFormula, lcShared, lnId, lcTemp, lnNdx, lcChr, lcAddExpr, lnCol, lcRef, lcRefBeg, lcRefEnd, llColRelative LOCAL lnColBase, llRowRelative, lnRowBase lcFormula = this.GetNodeElementValue(tcFormula) lcShared = this.GetNodeAttributeValue(tcFormula, "t") IF !EMPTY(lcShared) *-* The formula is a shared formula lnId = this.GetNodeAttributeValue(tcFormula, "si") IF EMPTY(lcFormula) IF SEEK(lnId, "t_shared", "id") *-* Shared formula already added; update the column:row relative references lcFormula = "" lcTemp = ALLTRIM(t_shared.cellformula) DO CASE CASE t_shared.colrelative && Forumla column is relative lnNdx = 1 DO WHILE lnNdx <= LEN(lcTemp) lcChr = SUBSTR(lcTemp, lnNdx, 1) IF ISALPHA(lcChr) lcAddExpr = lcChr DO WHILE lnNdx <= LEN(lcTemp) lnNdx = lnNdx + 1 lcChr = SUBSTR(lcTemp, lnNdx, 1) DO CASE CASE ISALPHA(lcChr) lcAddExpr = lcAddExpr + lcChr CASE ISDIGIT(lcChr) lnCol = this.ColumnAsciiToIndex(lcAddExpr) lnCol = lnCol + (tnCellCol - t_shared.colbase) lcAddExpr = this.ColumnIndexToAscii(lnCol) + lcChr EXIT OTHERWISE lcAddExpr = lcAddExpr + lcChr EXIT ENDCASE ENDDO ELSE lcAddExpr = lcChr ENDIF lcFormula = lcFormula + lcAddExpr lnNdx = lnNdx + 1 ENDDO CASE t_shared.rowrelative && Forumla row is relative lnNdx = 1 DO WHILE lnNdx <= LEN(lcTemp) lcChr = SUBSTR(lcTemp, lnNdx, 1) IF ISDIGIT(lcChr) lcAddExpr = lcChr DO WHILE lnNdx <= LEN(lcTemp) lnNdx = lnNdx + 1 lcChr = SUBSTR(lcTemp, lnNdx, 1) IF ISDIGIT(lcChr) lcAddExpr = lcAddExpr + lcChr ELSE IF ISALPHA(lcChr) lcAddExpr = lcAddExpr + lcChr ELSE lnRow = INT(VAL(lcAddExpr)) lnRow = lnRow + (lnCellRow - t_shared.rowbase) lcAddExpr = TRANSFORM(lnRow) + lcChr ENDIF EXIT ENDIF ENDDO ELSE lcAddExpr = lcChr ENDIF lcFormula = lcFormula + lcAddExpr lnNdx = lnNdx + 1 ENDDO ENDCASE ELSE lcFormula = "" ENDIF ELSE lcRef = this.GetNodeAttributeValue(tcFormula, "ref") IF !SEEK(lnId, "t_shared", "id") .AND. OCCURS(":", lcRef) > 0 lcRefBeg = this.GetColumnInColRowPair(GETWORDNUM(lcRef, 1, ":")) lcRefEnd = this.GetColumnInColRowPair(GETWORDNUM(lcRef, 2, ":")) IF lcRefBeg == lcRefEnd llColRelative = False lnColBase = 0 llRowRelative = True lnRowBase = this.GetRowInColRowPair(GETWORDNUM(lcRef, 1, ":")) ELSE llColRelative = True lnColBase = this.ColumnAsciiToIndex(lcRefBeg) llRowRelative = False lnRowBase = 0 ENDIF INSERT INTO t_shared (id, colrelative, colbase, rowrelative, rowbase, cellformula) ; VALUES (lnId, llColRelative, lnColBase, llRowRelative, lnRowBase, lcFormula) ENDIF ENDIF ENDIF RETURN lcFormula ENDPROC PROCEDURE getcellindent && Returns the cell indentation LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lnIndent IF PCOUNT() != 4 RETURN -1 ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnIndent = xl_cellxfs.indent ELSE lnIndent = 0 ENDIF RETURN lnIndent ENDPROC PROCEDURE getcellnumberformat && Returns the format code for the selected cell LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lnNumFmtId IF PCOUNT() != 4 RETURN -1 ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnNumFmtId = xl_cellxfs.numFmtId ELSE lnNumFmtId = 0 ENDIF RETURN lnNumFmtId ENDPROC PROCEDURE getcellnumberformattext && Returns the selected cell numeric format as text LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lcFormatCode IF PCOUNT() != 4 RETURN "" ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lcFormatCode = xl_cellxfs.formatcode ELSE lcFormatCode = "" ENDIF RETURN lcFormatCode ENDPROC PROTECTED PROCEDURE getcellrecord && Positions to the xl_cells record; returns true if found, or false if not found LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol RETURN SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnCellRow)+BINTOC(tnCellCol), "xl_cells", "cellindex") ENDPROC PROCEDURE getcellstyle && Gets the cell style value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol IF PCOUNT() = 4 .AND. this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) RETURN xl_cells.cellxfs ELSE RETURN -1 ENDIF ENDPROC PROCEDURE getcelltextrotation && Gets the cell text rotation value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lnRotation IF PCOUNT() != 4 RETURN 99 ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnRotation = xl_cellxfs.rotation IF lnRotation > 90 lnRotation = 90 - lnRotation ENDIF ELSE lnRotation = 0 ENDIF RETURN lnRotation ENDPROC PROCEDURE getcellvalidation && Returns the cell validation settings LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loValiation loValiation = CREATEOBJECT("Empty") ADDPROPERTY(loValiation, "Type", 0) ADDPROPERTY(loValiation, "Style", 0) ADDPROPERTY(loValiation, "Operator", 0) ADDPROPERTY(loValiation, "AllowBlank", False) ADDPROPERTY(loValiation, "ShowInputMsg", False) ADDPROPERTY(loValiation, "ShowErrMsg", False) ADDPROPERTY(loValiation, "ErrMsg", "") ADDPROPERTY(loValiation, "ErrTitle", "") ADDPROPERTY(loValiation, "Prompt", "") ADDPROPERTY(loValiation, "Formula1", "") ADDPROPERTY(loValiation, "Formula2", "") IF PCOUNT() < 4 RETURN loValiation ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. SEEK(BINTOC(xl_cells.validndx), "xl_validation", "validndx") loValiation.Type = xl_validation.vtype loValiation.Style = xl_validation.vstyle loValiation.Operator = xl_validation.voperator loValiation.AllowBlank = xl_validation.allowblank loValiation.ShowInputMsg = xl_validation.showinpmsg loValiation.ShowErrMsg = xl_validation.showerrmsg loValiation.ErrMsg = xl_validation.errmsg loValiation.ErrTitle = xl_validation.errtitle loValiation.Prompt = xl_validation.vprompt loValiation.Formula1 = xl_validation.formula1 loValiation.Formula2 = xl_validation.formula2 ENDIF RETURN loValiation ENDPROC PROCEDURE getcellvalue && Returns the value of the cell LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lxValue, lnDays, lnDecimals, lnMSec, lnTime, lnSize, lcType, loException IF PCOUNT() < 4 RETURN .NULL. ENDIF lxValue = .NULL. IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) lnDecimals = SET("DECIMALS") TRY DO CASE CASE xl_cells.datatype = DATA_TYPE_DATE lnDays = CAST(xl_cells.cellvalue AS I) lxValue = DATE(1900, 1, 1) + lnDays - 2 CASE xl_cells.datatype = DATA_TYPE_TIME SET DECIMALS TO 12 lnMSec = CAST(xl_cells.cellvalue AS N(20,12)) lnTime = lnMSec * 24 * 60 * 60 lxValue = DTOT(DATE()) + lnTime lxValue = TRANSFORM(HOUR(lxValue)) + ":" + TRANSFORM(MINUTE(lxValue)) + ":" + TRANSFORM(SEC(lxValue)) CASE xl_cells.datatype = DATA_TYPE_DATETIME SET DECIMALS TO 12 lnDays = CAST(xl_cells.cellvalue AS I) lxValue = DATE(1900, 1, 1) + lnDays - 2 lnMSec = CAST(xl_cells.cellvalue AS N(20,12)) - lnDays lnTime = lnMSec * 24 * 60 * 60 lxValue = DTOT(lxValue) + lnTime CASE xl_cells.datatype = DATA_TYPE_CHAR IF this.GetCursorRecord("xl_strings", tnWB, xl_cells.stringid) lxValue = RTRIM(xl_strings.stringval) ELSE lxValue = "" ENDIF CASE xl_cells.datatype = DATA_TYPE_INT lxValue = CAST(xl_cells.cellvalue AS I) IF lxValue != VAL(xl_cells.cellvalue) && Fix suggestion by Dan Lauer for integer values larger than VFP max lxValue = CAST(xl_cells.cellvalue AS N(20,0)) ENDIF CASE xl_cells.datatype = DATA_TYPE_FLOAT lnSize = ATC(".", ALLTRIM(xl_cells.cellvalue)) IF lnSize > 0 lnSize = lnSize + lnDecimals ELSE lnSize = LEN(ALLTRIM(xl_cells.cellvalue)) + lnDecimals + 1 ENDIF lcType = "N(" + TRANSFORM(lnSize) + "," + TRANSFORM(lnDecimals) + ")" lxValue = CAST(xl_cells.cellvalue AS &lcType) CASE xl_cells.datatype = DATA_TYPE_CURRENCY lxValue = CAST(xl_cells.cellvalue AS Y) CASE xl_cells.datatype = DATA_TYPE_PERCENT lxValue = CAST(xl_cells.cellvalue AS N(14,8)) lxValue = TRANSFORM(lxValue * 100) + "%" CASE xl_cells.datatype = DATA_TYPE_GENERAL lxValue = ALLTRIM(xl_cells.cellvalue) CASE xl_cells.datatype = DATA_TYPE_FORMULA CASE xl_cells.datatype = DATA_TYPE_NONE lxValue = ALLTRIM(xl_cells.cellvalue) OTHERWISE lxValue = ALLTRIM(xl_cells.cellvalue) ENDCASE CATCH TO loException SET STEP ON FINALLY SET DECIMALS TO &lnDecimals ENDTRY ENDIF RETURN lxValue ENDPROC PROCEDURE getcellwordwrap && Returns the cell word wrap setting LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL lxReturn IF PCOUNT() < 4 RETURN .NULL. ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lxReturn = xl_cellxfs.wraptext ELSE lxReturn = .NULL. ENDIF RETURN lxReturn ENDPROC PROTECTED PROCEDURE getcellxfsid && Returns the Cell XfsId value LPARAMETERS tnWB, tnNumFmtId, tnFontId, tnFillId, tnBorderId, tcHAlign, tcVAlign, tnIndex, tnWrapText, tnRotation LOCAL lnCellXfsId IF SEEK(BINTOC(tnWB)+BINTOC(tnNumFmtId)+BINTOC(tnFontId)+BINTOC(tnFillId)+BINTOC(tnBorderId)+BINTOC(tnIndex)+BINTOC(tnWrapText)+BINTOC(tnRotation)+ALLTRIM(tcHAlign)+ALLTRIM(tcVAlign), "xl_cellxfs", "cellxfs") lnCellXfsId = xl_cellxfs.id ELSE lnCellXfsId = this.GetNextId(tnWB, 'xl_cellxfs') INSERT INTO xl_cellxfs (workbook, id, numFmtId, fontId, fillId, borderId, halign, valign, indent, wraptext, rotation) ; VALUES (tnWB, lnCellXfsId, tnNumFmtId, tnFontId, tnFillId, tnBorderId, tcHAlign, tcVAlign, tnIndex, tnWrapText, tnRotation) ENDIF RETURN lnCellXfsId ENDPROC PROTECTED PROCEDURE getcellxfsrecord && Positions the record pointer to xl_cellxfs record; returns true if found, or false if not found LPARAMETERS tnWB, tnId RETURN SEEK(BINTOC(tnWB)+BINTOC(tnId), "xl_cellxfs", "id") ENDPROC PROTECTED PROCEDURE getchecksum && Returns the checksum the string LPARAMETERS tcString LOCAL lcString, lcCheckSum lcString = ALLTRIM(tcString) lcCheckSum = SYS(2007, lcString, 0, 1) lcCheckSum = lcCheckSum + PADR(lcString, (230-LEN(lcCheckSum)), "_") RETURN lcCheckSum ENDPROC PROTECTED PROCEDURE getchildnodecount && Returns the number of child nodes LPARAMETERS tcNode RETURN OCCURS("<", tcNode) - 2 ENDPROC PROTECTED PROCEDURE getchildnodeelement && Returns the selected child node LPARAMETERS tcNode, tnChild LOCAL lcElement lcElement = STREXTRACT(tcNode, '<', '>', tnChild+1, 1) RETURN STREXTRACT(tcNode, '<'+lcElement+'>', '', 1, 5) ENDPROC PROTECTED PROCEDURE getcolumnincolrowpair && Returns the column (Ascii value) in a ColRow pair; i.e., returns A from A6 reference LPARAMETERS tcColRow LOCAL lnNdx, lcCol, lcChr lcCol = "" FOR lnNdx=1 TO LEN(tcColRow) lcChr = SUBSTR(tcColRow, lnNdx, 1) IF ISDIGIT(lcChr) EXIT ENDIF lcCol = lcCol + lcChr ENDFOR RETURN lcCol ENDPROC PROCEDURE getcolumnwidth && Returns the column width LPARAMETERS tnWB, tnSheet, tnColumn LOCAL lxReturn IF PCOUNT() < 3 RETURN .NULL. ENDIF IF this.GetSheetRecord(tnWB, tnSheet) IF SEEK(this.GetColWidthKeyExpr(tnWB, tnSheet, tnColumn), "xl_colwidths", "shcolumn") lxReturn = xl_colwidths.width ELSE lxReturn = -1 ENDIF ELSE lxReturn = .NULL. ENDIF RETURN lxReturn ENDPROC PROTECTED PROCEDURE getcolwidthkeyexpr && Gets the key expression for c_colwidths LPARAMETERS tnWB, tnSheet, tnColumn RETURN BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnColumn) ENDPROC PROTECTED PROCEDURE getcursorrecord && Gets the specified xl_cursor record; returns true if found, false if not found LPARAMETERS tcCursor, tnWB, tnId RETURN SEEK(BINTOC(tnWB)+BINTOC(tnId), tcCursor, "id") ENDPROC PROCEDURE getcustomnumericformat && Returns the format code for the specified custom numeric format LPARAMETERS tnWB, tnNumFormat LOCAL lxReturn IF SEEK(BINTOC(tnWB)+BINTOC(tnNumFormat), "xl_numfmts", "id") lxReturn = ALLTRIM(xl_numfmts.formatcode) ELSE lxReturn = "" ENDIF RETURN lxReturn ENDPROC PROCEDURE getcustompapersize && Gets the values for the custom paper size LPARAMETERS tnWB, tnSheet LOCAL loReturn IF PCOUNT() = 2 .AND. this.GetSheetRecord(tnWB, tnSheet) loReturn = CREATEOBJECT("Empty") ADDPROPERTY(loReturn, "PaperWidth", xl_sheets.paperwidth) ADDPROPERTY(loReturn, "PaperHeight", xl_sheets.paperheight) ADDPROPERTY(loReturn, "PaperDimen", xl_sheets.paperdimen) ELSE loReturn = .NULL. ENDIF RETURN loReturn ENDPROC PROTECTED PROCEDURE getformatkeyexpr && Gets the key expression for t_format LPARAMETERS tnNbrFmtId, tnNumDec, tnFontId, tnFillId, tnBorderId, tcHAlign, tcVAlign, tlWordWrap RETURN BINTOC(tnNbrFmtId)+BINTOC(tnNumDec)+BINTOC(tnFontId)+BINTOC(tnFillId)+BINTOC(tnBorderId)+tcHAlign+tcVAlign+TRANSFORM(tlWordWrap) ENDPROC PROTECTED PROCEDURE getheaderfooterkeyexpr && Gets the key expression for the header footer table record LPARAMETERS tnWB, tnSheet, tnPage, tnSection RETURN BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnPage)+BINTOC(tnSection) ENDPROC PROCEDURE getinlinefontdefinition && Returns the inline formatting definition of cell text for each character group LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loSharedString, loInline, lcAlias, lnBegPos, lnLen, loCharacter IF PCOUNT() != 4 RETURN .NULL. ENDIF loSharedString = this.GetSharedStringId(tnWB, tnSheet, tnCellRow, tnCellCol) IF ISNULL(loSharedString) RETURN .NULL. ENDIF lnBegPos = 1 lcAlias = ALIAS() loInline = CREATEOBJECT("Empty") ADDPROPERTY(loInline, "Workbook", tnWB) ADDPROPERTY(loInline, "StringId", loSharedString.StringId) ADDPROPERTY(loInline, "StringValue", loSharedString.StringValue) ADDPROPERTY(loInline, "Count", 0) ADDPROPERTY(loInline, "Characters[1]") SELECT xl_strformat SET ORDER TO TAG sortorder SCAN FOR workbook = tnWB .AND. id = loSharedString.StringId .AND. !DELETED() lnLen = LEN(RTRIM(xl_strformat.stringxml)) loCharacter = CREATEOBJECT("Empty") ADDPROPERTY(loCharacter, "BegPos", lnBegPos) ADDPROPERTY(loCharacter, "Length", lnLen) ADDPROPERTY(loCharacter, "FontName", xl_strformat.fname) ADDPROPERTY(loCharacter, "FontSize", xl_strformat.fsize) ADDPROPERTY(loCharacter, "FontBold", xl_strformat.fbold) ADDPROPERTY(loCharacter, "FontItalic", xl_strformat.fitalic) ADDPROPERTY(loCharacter, "FontColor", xl_strformat.fcolor) ADDPROPERTY(loCharacter, "Underline", xl_strformat.uline) ADDPROPERTY(loCharacter, "StrikeThru", xl_strformat.strkthr) ADDPROPERTY(loCharacter, "SubScript", IIF(xl_strformat.fvpos=FONT_VERTICAL_SUBSCRIPT, True, False)) ADDPROPERTY(loCharacter, "SuperScript", IIF(xl_strformat.fvpos=FONT_VERTICAL_SUPERSCRIPT, True, False)) loInline.Count = loInline.Count + 1 DIMENSION loInline.Characters[loInline.Count] loInline.Characters[loInline.Count] = loCharacter lnBegPos = lnBegPos + lnLen ENDSCAN SET ORDER TO IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF IF loInline.Count = 0 loInline = .NULL. ENDIF RETURN loInline ENDPROC PROCEDURE getlastcolumninrow && Returns the last column index in the row LPARAMETERS tnWB, tnSheet, tnCellRow LOCAL lnMaxCol IF PCOUNT() < 3 RETURN .NULL. ENDIF lnMaxCol = 0 SELECT MAX(tmp.cellcol) AS maxcol FROM xl_cells AS tmp ; WHERE workbook = tnWB ; AND tmp.sheet = tnSheet ; AND tmp.cellrow = tnCellRow ; AND tmp.celldeleted = False ; INTO CURSOR t_temp IF _TALLY > 0 lnMaxCol = t_temp.maxcol ENDIF IF USED('t_temp') USE IN t_temp ENDIF RETURN lnMaxCol ENDPROC PROCEDURE getlastrownumber && Returns the last row number in the sheet LPARAMETERS tnWB, tnSheet LOCAL lnLastRow LOCAL ARRAY laMaxRow[1] IF PCOUNT() < 2 RETURN .NULL. ENDIF SELECT MAX(cellrow) FROM xl_cells ; WHERE workbook = tnWB ; AND sheet = tnSheet ; AND celldeleted = False ; INTO ARRAY laMaxRow IF _TALLY > 0 lnLastRow = laMaxRow[1] ELSE lnLastRow = 0 ENDIF RETURN lnLastRow ENDPROC PROCEDURE getmaxcolumnnumber && Returns the max column number for a sheet LPARAMETERS tnWB, tnSheet LOCAL lnMaxCol LOCAL ARRAY laMaxCol[1] IF PCOUNT() < 2 RETURN .NULL. ENDIF SELECT MAX(tmp.maxcol) AS maxcol FROM xl_rows AS tmp ; WHERE tmp.workbook = tnWB ; AND tmp.sheet = tnSheet ; INTO ARRAY laMaxCol IF _TALLY > 0 lnMaxCol = laMaxCol[1] ELSE lnMaxCol = 0 ENDIF RETURN NVL(lnMaxCol, 0) ENDPROC PROTECTED PROCEDURE getnextid && Gets the next sequential Id value LPARAMETERS tnWB, tcCursor LOCAL lnNdx, lnNextId DO CASE CASE tcCursor = "xl_borders" lnNdx = ASCAN(this.LastBorderId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastBorderId[lnNdx, 2] = this.LastBorderId[lnNdx, 2] + 1 lnNextId = this.LastBorderId[lnNdx, 2] ELSE IF this.LastBorderId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastBorderId, 1) + 1 ENDIF DIMENSION this.LastBorderId[lnNdx, 2] this.LastBorderId[lnNdx, 1] = tnWB this.LastBorderId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_cellxfs" lnNdx = ASCAN(this.LastCellXfsId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastCellXfsId[lnNdx, 2] = this.LastCellXfsId[lnNdx, 2] + 1 lnNextId = this.LastCellXfsId[lnNdx, 2] ELSE IF this.LastCellXfsId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastCellXfsId, 1) + 1 ENDIF DIMENSION this.LastCellXfsId[lnNdx, 2] this.LastCellXfsId[lnNdx, 1] = tnWB this.LastCellXfsId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_fills" lnNdx = ASCAN(this.LastFillId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastFillId[lnNdx, 2] = this.LastFillId[lnNdx, 2] + 1 lnNextId = this.LastFillId[lnNdx, 2] ELSE IF this.LastFillId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastFillId, 1) + 1 ENDIF DIMENSION this.LastFillId[lnNdx, 2] this.LastFillId[lnNdx, 1] = tnWB this.LastFillId[lnNdx, 2] = 2 lnNextId = 2 ENDIF CASE tcCursor = "xl_fonts" lnNdx = ASCAN(this.LastFontId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastFontId[lnNdx, 2] = this.LastFontId[lnNdx, 2] + 1 lnNextId = this.LastFontId[lnNdx, 2] ELSE IF this.LastFontId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastFontId, 1) + 1 ENDIF DIMENSION this.LastFontId[lnNdx, 2] this.LastFontId[lnNdx, 1] = tnWB this.LastFontId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_ndxcolors" lnNdx = ASCAN(this.LastIndexColorId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastIndexColorId[lnNdx, 2] = this.LastIndexColorId[lnNdx, 2] + 1 lnNextId = this.LastIndexColorId[lnNdx, 2] ELSE IF this.LastIndexColorId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastIndexColorId, 1) + 1 ENDIF DIMENSION this.LastIndexColorId[lnNdx, 2] this.LastIndexColorId[lnNdx, 1] = tnWB this.LastIndexColorId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_mrucolors" lnNdx = ASCAN(this.LastMruColorId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastMruColorId[lnNdx, 2] = this.LastMruColorId[lnNdx, 2] + 1 lnNextId = this.LastMruColorId[lnNdx, 2] ELSE IF this.LastMruColorId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastMruColorId, 1) + 1 ENDIF DIMENSION this.LastMruColorId[lnNdx, 2] this.LastMruColorId[lnNdx, 1] = tnWB this.LastMruColorId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_numfmts" lnNdx = ASCAN(this.LastNumFmtId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastNumFmtId[lnNdx, 2] = this.LastNumFmtId[lnNdx, 2] + 1 lnNextId = this.LastNumFmtId[lnNdx, 2] ELSE IF this.LastNumFmtId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastNumFmtId, 1) + 1 ENDIF DIMENSION this.LastNumFmtId[lnNdx, 2] this.LastNumFmtId[lnNdx, 1] = tnWB this.LastNumFmtId[lnNdx, 2] = START_NUMERIC_FORMAT_ID lnNextId = START_NUMERIC_FORMAT_ID ENDIF CASE tcCursor = "xl_relationships" lnNdx = ASCAN(this.LastRelationId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastRelationId[lnNdx, 2] = this.LastRelationId[lnNdx, 2] + 1 lnNextId = this.LastRelationId[lnNdx, 2] ELSE IF this.LastRelationId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastRelationId, 1) + 1 ENDIF DIMENSION this.LastRelationId[lnNdx, 2] this.LastRelationId[lnNdx, 1] = tnWB this.LastRelationId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_sheets" lnNdx = ASCAN(this.LastSheetId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastSheetId[lnNdx, 2] = this.LastSheetId[lnNdx, 2] + 1 lnNextId = this.LastSheetId[lnNdx, 2] ELSE IF this.LastSheetId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastSheetId, 1) + 1 ENDIF DIMENSION this.LastSheetId[lnNdx, 2] this.LastSheetId[lnNdx, 1] = tnWB this.LastSheetId[lnNdx, 2] = 1 lnNextId = 1 ENDIF CASE tcCursor = "xl_strings" lnNdx = ASCAN(this.LastStringId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastStringId[lnNdx, 2] = this.LastStringId[lnNdx, 2] + 1 lnNextId = this.LastStringId[lnNdx, 2] ELSE IF this.LastStringId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastStringId, 1) + 1 ENDIF DIMENSION this.LastStringId[lnNdx, 2] this.LastStringId[lnNdx, 1] = tnWB this.LastStringId[lnNdx, 2] = 0 lnNextId = 0 ENDIF OTHERWISE lnNextId = 0 ENDCASE RETURN lnNextId ENDPROC PROTECTED PROCEDURE getnodeattributevalue && Returns the attribute value LPARAMETERS tcXf, tcAttrName RETURN STREXTRACT(tcXf, tcAttrName+'="', '"', 1) ENDPROC PROTECTED PROCEDURE getnodecount && Returns the number of nodes to be processed LPARAMETERS tcNode, tcElement LOCAL lnCount lnCount = OCCURS("<"+tcElement+">", tcNode) IF lnCount = 0 lnCount = OCCURS("<"+tcElement+" ", tcNode) IF lnCount = 0 lnCount = OCCURS("<"+tcElement, tcNode) ENDIF ENDIF RETURN lnCount ENDPROC PROTECTED PROCEDURE getnodeelement && Gets the string content for the node element LPARAMETERS tcNode, tcElement, tnNode, tlStrict, tnFlag LOCAL lcContent, lnNdx, loException DO CASE CASE PCOUNT() = 3 tlStrict = False tnFlag = 5 CASE PCOUNT() = 4 tnFlag = 5 ENDCASE IF tlStrict lcContent = STREXTRACT(tcNode, "<"+tcElement+">", "", tnNode, tnFlag) ELSE lcContent = STREXTRACT(tcNode, "<"+tcElement+" ", ">", tnNode, tnFlag) IF RIGHT(lcContent, 2) != "/>" lcContent = STREXTRACT(tcNode, "<"+tcElement+" ", "", tnNode, tnFlag) IF EMPTY(lcContent) lcContent = STREXTRACT(tcNode, "<"+tcElement+">", "", tnNode, tnFlag) ENDIF IF EMPTY(lcContent) lcContent = STREXTRACT(tcNode, "<"+tcElement, "/>", tnNode, tnFlag) ENDIF ENDIF ENDIF RETURN lcContent ENDPROC PROTECTED PROCEDURE getnodeelementvalue && Gets the value assigned to the node element LPARAMETERS tcElement RETURN STREXTRACT(tcElement, '>', '<', 1, 1) ENDPROC PROCEDURE getnumberofsheets && Returns the number of sheets for the given workbook LPARAMETERS tnWB LOCAL lnCount SELECT xl_sheets COUNT FOR xl_sheets.workbook = tnWB .AND. !xl_sheets.shdeleted TO lnCount RETURN lnCount ENDPROC PROCEDURE getpapersize && Gets the paper size for the selected sheet LPARAMETERS tnWB, tnSheet LOCAL lxReturn IF PCOUNT() = 2 .AND. this.GetSheetRecord(tnWB, tnSheet) lxReturn = xl_sheets.papersize ELSE lxReturn = -1 ENDIF RETURN lxReturn ENDPROC PROCEDURE getprintorientation && Gets the print orientation for the sheet output LPARAMETERS tnWB, tnSheet LOCAL lxReturn IF PCOUNT() = 2 .AND. this.GetSheetRecord(tnWB, tnSheet) lxReturn = xl_sheets.prnorient ELSE lxReturn = 0 ENDIF RETURN lxReturn ENDPROC PROTECTED PROCEDURE getrelationshipfilename && Gets the file name for the R:Id value in the relationships XML LPARAMETERS tnWB, tnShRId LOCAL lcFileName lcFileName = "" IF SEEK(BINTOC(tnWB)+BINTOC(tnShRId), "xl_relationships", "relid") lcFileName = ALLTRIM(xl_relationships.target) ENDIF RETURN lcFileName ENDPROC PROCEDURE getrgbvalues && Gets the specified RGB color value LPARAMETERS tnColorValue, tcRGB LOCAL lnValue, lnNdx IF PCOUNT() < 2 RETURN -1 ENDIF DO CASE CASE tcRGB = "R" lnValue = tnColorValue FOR lnNdx=8 TO 31 lnValue = BITCLEAR(lnValue, lnNdx) ENDFOR CASE tcRGB = "G" lnValue = BITRSHIFT(tnColorValue, 8) FOR lnNdx=8 TO 31 lnValue = BITCLEAR(lnValue, lnNdx) ENDFOR CASE tcRGB = "B" lnValue = BITRSHIFT(tnColorValue, 16) FOR lnNdx=8 TO 31 lnValue = BITCLEAR(lnValue, lnNdx) ENDFOR OTHERWISE RETURN -1 ENDCASE RETURN INT(lnValue) ENDPROC PROTECTED PROCEDURE getrowheightkeyexpr && Gets the key expression for the c_rowheights LPARAMETERS tnWB, tnSheet, tnRow RETURN BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnRow) ENDPROC PROTECTED PROCEDURE getrowincolrowpair && REturns the row (integer value) in a ColRow pair; i.e., return 6 from A6 reference LPARAMETERS tcColRow LOCAL lcRow, lnNdx, lcChr lcRow = "" FOR lnNdx=1 TO LEN(tcColRow) lcChr = SUBSTR(tcColRow, lnNdx, 1) IF ISDIGIT(lcChr) lcRow = lcRow + lcChr ENDIF ENDFOR RETURN INT(VAL(lcRow)) ENDPROC PROCEDURE getrowmaxcolumn && Returns the selected row maximum column LPARAMETERS tnWB, tnSheet, tnCellRow LOCAL lnMaxCol IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnCellRow), "xl_rows", "id") lnMaxCol = xl_rows.maxcol ELSE lnMaxCol = 0 ENDIF RETURN lnMaxCol ENDPROC PROTECTED PROCEDURE getsharedstringid && Gets the Shared Strings Id value for the cell text LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL loSharedString loSharedString = .NULL. IF PCOUNT() < 4 RETURN loSharedString ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) .AND. this.GetCursorRecord("xl_strings", tnWB, xl_cells.stringid) loSharedString = CREATEOBJECT("Empty") ADDPROPERTY(loSharedString, "StringId", xl_cells.stringid) ADDPROPERTY(loSharedString, "StringValue", xl_strings.stringval) ENDIF RETURN loSharedString ENDPROC PROCEDURE getsheetname && Gets the sheet name LPARAMETERS tnWB, tnSheet LOCAL lcSheetName IF PCOUNT() = 2 .AND. this.GetSheetRecord(tnWB, tnSheet) lcSheetName = ALLTRIM(xl_sheets.shname) ELSE lcSheetName = "" ENDIF RETURN lcSheetName ENDPROC PROTECTED PROCEDURE getsheetrecord && Positions the record in xl_sheets; returns true if record found, or false if not found LPARAMETERS tnWB, tnSheet RETURN SEEK(BINTOC(tnWB)+BINTOC(tnSheet), "xl_sheets", "sheetndx") ENDPROC PROCEDURE getsheetrowvalues && Returns the cell values for the given row LPARAMETERS tnWB, tnSheet, tnCellRow LOCAL lnMaxCol, loRow IF PCOUNT() < 3 RETURN .NULL. ENDIF lnMaxCol = this.GetMaxColumnNumber(tnWB, tnSheet) IF !ISNULL(lnMaxCol) .AND. lnMaxCol > 0 loRow = CREATEOBJECT("Empty") ADDPROPERTY(loRow, "Values[lnMaxCol, 2]", "") ADDPROPERTY(loRow, "Count", lnMaxCol) loRow.Values = .NULL. SELECT tmp.cellcol FROM xl_cells AS tmp ; WHERE workbook = tnWB ; AND tmp.sheet = tnSheet ; AND tmp.cellrow = tnCellRow ; AND tmp.celldeleted = False ; INTO CURSOR t_temp SELECT t_temp SCAN loRow.Values[t_temp.cellcol, 1] = this.GetCellValue(tnWB, tnSheet, tnCellRow, t_temp.cellcol) loRow.Values[t_temp.cellcol, 2] = this.GetCellDataType(tnWB, tnSheet, tnCellRow, t_temp.cellcol) ENDSCAN USE IN t_temp ELSE loRow = .NULL. ENDIF RETURN loRow ENDPROC PROCEDURE getsheetscale && Gets the sheet printing scale LPARAMETERS tnWB, tnSheet LOCAL lxReturn IF PCOUNT() = 2 .AND. this.GetSheetRecord(tnWB, tnSheet) lxReturn = xl_sheets.scale ELSE lxReturn = -1 ENDIF RETURN lxReturn ENDPROC PROTECTED PROCEDURE getstringrecord && Positions the record pointer to the selected string record LPARAMETERS tnWB, tcString RETURN SEEK(BINTOC(tnWB)+this.GetCheckSum(tcString), "xl_strings", "stringndx") ENDPROC PROTECTED PROCEDURE getstringxml && Returns a converted string from XML to text LPARAMETERS tcString LOCAL lcString, lcOldChr, lcChr, lnChr, lnNdx IF LEFT(tcString, 1) != " " .AND. EMPTY(tcString) RETURN "" ENDIF TRY IF ISNULL(this.oXDOM) lcString = STRTRAN(tcString, '&', CHR(38)) lcString = STRTRAN(lcString, '>', '>') lcString = STRTRAN(lcString, '<', '<') lcString = STRTRAN(lcString, '"', '"') lnNdx = 1 DO WHILE ATC("&#", lcString, lnNdx) > 0 lcOldChr = STREXTRACT(lcString, "&#", ";", lnNdx) lnChr = INT(VAL(lcOldChr)) IF lnChr < 256 lcChr = CHR(lnChr) lcOldChr = "&#" + lcOldChr + ";" lcString = STRTRAN(lcString, lcOldChr, lcChr) ELSE lnNdx = lnNdx + 1 && Increment to skip this embedded value ENDIF ENDDO ELSE this.oXDOM.loadXML("" + tcString + "") lcString = this.oXDOM.Text ENDIF CATCH TO loException SET STEP ON ENDTRY RETURN lcString ENDPROC PROCEDURE getvalidation && Returns the validation definition LPARAMETERS tnValidNdx LOCAL loValiation loValiation = CREATEOBJECT("Empty") ADDPROPERTY(loValiation, "Type", 0) ADDPROPERTY(loValiation, "Style", 0) ADDPROPERTY(loValiation, "Operator", 0) ADDPROPERTY(loValiation, "AllowBlank", False) ADDPROPERTY(loValiation, "ShowInputMsg", False) ADDPROPERTY(loValiation, "ShowErrMsg", False) ADDPROPERTY(loValiation, "ErrMsg", "") ADDPROPERTY(loValiation, "ErrTitle", "") ADDPROPERTY(loValiation, "Prompt", "") ADDPROPERTY(loValiation, "Formula1", "") ADDPROPERTY(loValiation, "Formula2", "") IF PCOUNT() < 1 RETURN loValiation ENDIF IF SEEK(BINTOC(tnValidNdx), "xl_validation", "validndx") loValiation.Type = xl_validation.vtype loValiation.Style = xl_validation.vstyle loValiation.Operator = xl_validation.voperator loValiation.AllowBlank = xl_validation.allowblank loValiation.ShowInputMsg = xl_validation.showinpmsg loValiation.ShowErrMsg = xl_validation.showerrmsg loValiation.ErrMsg = xl_validation.errmsg loValiation.ErrTitle = xl_validation.errtitle loValiation.Prompt = xl_validation.vprompt loValiation.Formula1 = IIF(xl_validation.formula, "=", "") + ALLTRIM(xl_validation.formula1) loValiation.Formula2 = IIF(EMPTY(xl_validation.formula2), "", IIF(xl_validation.formula, "=", "") + ALLTRIM(xl_validation.formula2)) ENDIF RETURN loValiation ENDPROC PROCEDURE getvalidationlist && Returns a list of validations for the workbook/sheet LPARAMETERS tnWB, tnSheet LOCAL loValiation, lcAlias lcAlias = ALIAS() loValiation = CREATEOBJECT("Empty") ADDPROPERTY(loValiation, "List[1]") ADDPROPERTY(loValiation, "Count", 0) SELECT xl_validation SCAN FOR BINTOC(workbook)+BINTOC(sheet) loValiation.Count = loValiation.Count + 1 DIMENSION loValiation.List[loValiation.Count, 2] loValiation.List[loValiation.Count, 1] = xl_validation.vtype loValiation.List[loValiation.Count, 2] = xl_validation.validndx ENDSCAN IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN loValiation ENDPROC PROCEDURE getworkbook && Gets the workbook Id from the name LPARAMETERS tcName LOCAL lcWBName, lnWBIndex lcWBName = JUSTSTEM(tcName) IF SEEK(PADR(UPPER(lcWBName), 200, "_"), "xl_workbooks", "wbname") lnWBIndex = xl_workbooks.workbook ELSE lnWBIndex = 0 ENDIF RETURN lnWBIndex ENDPROC PROCEDURE getworkbookfilename && Gets the file name for the workbook index LPARAMETERS tnWB LOCAL lcFileName IF SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") lcFileName = ADDBS(ALLTRIM(xl_workbooks.filepath)) + ALLTRIM(xl_workbooks.wbname) lcFileName = FORCEEXT(lcFileName, "xlsx") ELSE lcFileName = "" ENDIF ENDPROC PROCEDURE getworkbooksheets && Returns the workbook sheets LPARAMETERS tnWB LOCAL loSheets loSheets = CREATEOBJECT("Empty") ADDPROPERTY(loSheets, "List[1, 2]") ADDPROPERTY(loSheets, "Count", 0) SELECT xl_sheets SET ORDER TO TAG sheet SCAN FOR workbook = tnWB .AND. !shdeleted loSheets.Count = loSheets.Count + 1 DIMENSION loSheets.List[loSheets.Count, 2] loSheets.List[loSheets.Count, 1] = xl_sheets.sheet loSheets.List[loSheets.Count, 2] = ALLTRIM(xl_sheets.shname) ENDSCAN SET ORDER TO RETURN loSheets ENDPROC PROTECTED PROCEDURE getxmlheaderfootertext && Returns a XML formatted string for the header and footer text LOCAL lcText IF EMPTY(xl_hdrfootertext.fontname) lcText = '"-,' ELSE lcText = '"' + ALLTRIM(xl_hdrfootertext.fontname) + ',' ENDIF DO CASE CASE xl_hdrfootertext.fontstyle = HEADERFOOTER_FONT_STYLE_BOLD lcText = lcText + 'Bold"' CASE xl_hdrfootertext.fontstyle = HEADERFOOTER_FONT_STYLE_ITALIC lcText = lcText + 'Italic"' CASE xl_hdrfootertext.fontstyle = HEADERFOOTER_FONT_STYLE_BOLDITALIC lcText = lcText + 'Bold Italic"' OTHERWISE lcText = lcText + 'Regular"' ENDCASE IF xl_hdrfootertext.fontsize > 0 lcText = lcText + '&' + TRANSFORM(xl_hdrfootertext.fontsize) ENDIF IF xl_hdrfootertext.fontcolor > 0 lcText = lcText + '&K' + this.ConvertColorToHex(xl_hdrfootertext.fontcolor) ENDIF lcText = lcText + ALLTRIM(xl_hdrfootertext.text) RETURN lcText ENDPROC PROTECTED PROCEDURE getxmlstring && Gets the string as an XML formatted string LPARAMETERS tcString LOCAL lcString, lcXMLString, lnNdx, lcChar, lcInvalidChars, loNodeText IF LEFT(tcString, 1) != " " .AND. EMPTY(tcString) RETURN "" ENDIF *-* TJF 2016-12-12 Strip out invalid XML characters (ASCII 0 to 31 except 9 (TAB), 10 (LF), and 13 (CR)) lcInvalidChars = CHR(0) + CHR(1) + CHR(2) + CHR(3) + CHR(4) + CHR(5) + CHR(6) + CHR(7) + CHR(8) + CHR(11) + CHR(12) + ; CHR(14) + CHR(15) + CHR(16) + CHR(17) + CHR(18) + CHR(19) + CHR(20) + CHR(21) + CHR(22) + CHR(23) + ; CHR(24) + CHR(25) + CHR(26) + CHR(27) + CHR(28) + CHR(29) + CHR(30) + CHR(31) lcString = CHRTRAN(tcString, lcInvalidChars, "") IF ISNULL(this.oXDOM) lcString = STRTRAN(lcString, CHR(38), '&') lcString = STRTRAN(lcString, '>', '>') lcString = STRTRAN(lcString, '<', '<') lcString = STRTRAN(lcString, '"', '"') IF this.CodePage = 0 lcXMLString = "" FOR lnNdx=1 TO LEN(lcString) lcChar = SUBSTR(lcString, lnNdx, 1) lnChar = ASC(lcChar) lcXMLString = lcXMLString + IIF(lnChar < 128, lcChar, "&#" + TRANSFORM(lnChar) + ";") ENDFOR ELSE lcXMLString = lcString ENDIF ELSE loNodeText = this.oXDOM.createTextNode(lcString) lcXMLString = loNodeText.xml lcXMLString = STRTRAN(lcXMLString, '"', '"') ENDIF RETURN lcXMLString ENDPROC PROTECTED PROCEDURE Init LPARAMETERS tnCodePage LOCAL loException, lnSelect IF PCOUNT() > 0 .AND. VARTYPE(tnCodePage) = "N" this.CodePage = tnCodePage ENDIF lnSelect = SELECT() this.CreateWorkingCursors() IF this.DeclareWinAPI this.DeclareDLL() ENDIF TRY this.oXDOM = CREATEOBJECT('MSXML2.DOMDocument') CATCH TO loException this.oXDOM = .NULL. ENDTRY this.InitalizeIdValues() this.OnInit() SELECT (lnSelect) ENDPROC PROTECTED PROCEDURE initalizeidvalues && Initializes the internal Id values DIMENSION this.LastBorderId[1, 2] this.LastBorderId[1, 1] = 0 && Workbook Id this.LastBorderId[1, 2] = 0 && Last Border Id DIMENSION this.LastCellXfsId[1, 2] this.LastCellXfsId[1, 1] = 0 && Workbook Id this.LastCellXfsId[1, 2] = 0 && Last CellXfs Id DIMENSION this.LastFillId[1, 2] this.LastFillId[1, 1] = 0 && Workbook Id this.LastFillId[1, 2] = 0 && Last Fill Id DIMENSION this.LastFontId[1, 2] this.LastFontId[1, 1] = 0 && Workbook Id this.LastFontId[1, 2] = 0 && Last Font Id DIMENSION this.LastIndexColorId[1, 2] this.LastIndexColorId[1, 1] = 0 && Workbook Id this.LastIndexColorId[1, 2] = 0 && Last IndexColor Id DIMENSION this.LastMruColorId[1, 2] this.LastMruColorId[1, 1] = 0 && Workbook Id this.LastMruColorId[1, 2] = 0 && Last mruColor Id DIMENSION this.LastNumFmtId[1, 2] this.LastNumFmtId[1, 1] = 0 && Workbook Id this.LastNumFmtId[1, 2] = 0 && Last NumFmt Id DIMENSION this.LastRelationId[1, 2] this.LastRelationId[1, 1] = 0 && Workbook Id this.LastRelationId[1, 2] = 0 && Last Relationship Id DIMENSION this.LastSheetId[1, 2] this.LastSheetId[1, 1] = 0 && Workbook Id this.LastSheetId[1, 2] = 0 && Last Sheet Id DIMENSION this.LastStringId[1, 2] this.LastStringId[1, 1] = 0 && Workbook Id this.LastStringId[1, 2] = 0 && Last String Id ENDPROC PROCEDURE insertcell && Inserts a new cell into the sheet LPARAMETERS tnWB, tnSheet, tnRow, tnCol, tnShift LOCAL llReturn, lnRow IF PCOUNT() < 5 RETURN False ENDIF IF this.GetSheetRecord(tnWB, tnSheet) SELECT xl_cells SET ORDER TO TAG reverse DO CASE CASE tnShift = INSERT_LEFT SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellcol >= tnCol .AND. cellrow = tnRow REPLACE xl_cells.cellcol WITH xl_cells.cellcol + 1 IN xl_cells this.SetRowMaxColumn(tnWB, tnSheet, xl_cells.cellrow, xl_cells.cellcol) ENDSCAN llReturn = True CASE tnShift = INSERT_RIGHT SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellcol > tnCol .AND. cellrow = tnRow REPLACE xl_cells.cellcol WITH xl_cells.cellcol + 1 IN xl_cells this.SetRowMaxColumn(tnWB, tnSheet, xl_cells.cellrow, xl_cells.cellcol) ENDSCAN llReturn = True CASE tnShift = INSERT_BEFORE SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellrow >= tnRow .AND. cellcol = tnCol REPLACE xl_cells.cellrow WITH xl_cells.cellrow + 1 IN xl_cells this.SetRowMaxColumn(tnWB, tnSheet, xl_cells.cellrow, xl_cells.cellcol) ENDSCAN llReturn = True CASE tnShift = INSERT_AFTER SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellrow > tnRow .AND. cellcol = tnCol REPLACE xl_cells.cellrow WITH xl_cells.cellrow + 1 IN xl_cells this.SetRowMaxColumn(tnWB, tnSheet, xl_cells.cellrow, xl_cells.cellcol) ENDSCAN llReturn = True OTHERWISE llReturn = False ENDCASE SET ORDER TO ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE insertcolumn && Inserts a new column into the sheet LPARAMETERS tnWB, tnSheet, tnCol, tnShift LOCAL llReturn IF PCOUNT() < 4 RETURN False ENDIF IF this.GetSheetRecord(tnWB, tnSheet) SELECT xl_cells SET ORDER TO TAG reverse DO CASE CASE tnShift = INSERT_LEFT SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellcol >= tnCol REPLACE xl_cells.cellcol WITH xl_cells.cellcol + 1 IN xl_cells IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(xl_cells.cellrow), "xl_rows", "id") .AND. xl_cells.cellcol > xl_rows.maxcol REPLACE xl_rows.maxcol WITH xl_cells.cellcol IN xl_rows ENDIF ENDSCAN llReturn = True CASE tnShift = INSERT_RIGHT SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellcol > tnCol REPLACE xl_cells.cellcol WITH xl_cells.cellcol + 1 IN xl_cells IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(xl_cells.cellrow), "xl_rows", "id") .AND. xl_cells.cellcol > xl_rows.maxcol REPLACE xl_rows.maxcol WITH xl_cells.cellcol IN xl_rows ENDIF ENDSCAN llReturn = True OTHERWISE llReturn = False ENDCASE SET ORDER TO ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE insertrow && Inserts a new row into the sheet LPARAMETERS tnWB, tnSheet, tnRow, tnShift LOCAL llReturn, lnRow IF PCOUNT() < 4 RETURN False ENDIF IF this.GetSheetRecord(tnWB, tnSheet) SELECT xl_cells SET ORDER TO TAG reverse DO CASE CASE tnShift = INSERT_BEFORE SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellrow >= tnRow lnRow = xl_cells.cellrow REPLACE xl_cells.cellrow WITH lnRow + 1 IN xl_cells IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(lnRow), "xl_rows", "id") REPLACE xl_rows.row WITH xl_cells.cellrow IN xl_rows ENDIF ENDSCAN llReturn = True CASE tnShift = INSERT_AFTER SCAN FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellrow > tnRow lnRow = xl_cells.cellrow REPLACE xl_cells.cellrow WITH lnRow + 1 IN xl_cells IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(lnRow), "xl_rows", "id") REPLACE xl_rows.row WITH xl_cells.cellrow IN xl_rows ENDIF ENDSCAN llReturn = True OTHERWISE llReturn = False ENDCASE SET ORDER TO ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE iscellformula && Returns True if cell contains a formula LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol LOCAL llFormula IF PCOUNT() < 4 RETURN .NULL. ENDIF llFormula = False IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) llFormula = !EMPTY(xl_cells.cellformula) ENDIF RETURN llFormula ENDPROC PROTECTED PROCEDURE iscellreferenceinvalid && Checks if the cell reference is invalid (outside of limits) LPARAMETERS tnRow, tnCol IF tnRow > LIMITS_MAX_ROWS .OR. tnCol > LIMITS_MAX_COLUMNS RETURN True ENDIF RETURN False ENDPROC PROCEDURE isformatstyledefined && Determines if the format is defined as a style LPARAMETERS tnWB, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos DO CASE CASE PCOUNT() < 3 RETURN .NULL. CASE PCOUNT() = 3 tlBold = False tlItalic = False tnFColor = RGB(0, 0, 0) tcULine = UNDERLINE_NONE tlStrikThr = False tcVPos = FONT_VERTICAL_BASELINE CASE PCOUNT() = 4 tlItalic = False tnFColor = RGB(0, 0, 0) tcULine = UNDERLINE_NONE tlStrikThr = False tcVPos = FONT_VERTICAL_BASELINE CASE PCOUNT() = 5 tnFColor = RGB(0, 0, 0) tcULine = UNDERLINE_NONE tlStrikThr = False tcVPos = FONT_VERTICAL_BASELINE CASE PCOUNT() = 6 tcULine = UNDERLINE_NONE tlStrikThr = False tcVPos = FONT_VERTICAL_BASELINE CASE PCOUNT() = 7 tlStrikThr = False tcVPos = FONT_VERTICAL_BASELINE CASE PCOUNT() = 8 tcVPos = FONT_VERTICAL_BASELINE ENDCASE IF SEEK(BINTOC(tnWB)+PADR(tcFName, 100) + STR(tnFSize, 5, 1) + TRANSFORM(tlBold) + TRANSFORM(tlItalic) + PADL(tnFColor, 15) + PADR(tcULine, 16) + ; TRANSFORM(tlStrikThr) + PADR(tcVPos, 11), "xl_fonts", "cellformat") IF SEEK(BINTOC(tnWB)+BINTOC(xl_fonts.id)+BINTOC(0)+BINTOC(0)+BINTOC(0)+BINTOC(0)+BINTOC(0), "xl_cellxfs", "cellformat") RETURN xl_cellxfs.id ELSE RETURN .NULL. ENDIF ELSE RETURN .NULL. ENDIF ENDPROC PROTECTED PROCEDURE isvalidborderstyle && Validates the border style value LPARAMETERS tcStyle IF VARTYPE(tcStyle) != 'C' .OR. EMPTY(tcStyle) .OR. !INLIST(tcStyle, BORDER_STYLE_THIN, BORDER_STYLE_HAIR, BORDER_STYLE_DOTTED, BORDER_STYLE_DASHDOTDOT, ; BORDER_STYLE_DASHDOT, BORDER_STYLE_DASHED, BORDER_STYLE_THIN, BORDER_STYLE_MEDIUMDASHDOTDOT, ; BORDER_STYLE_SLANTDASHDOT, BORDER_STYLE_MEDIUMDASHDOT, BORDER_STYLE_MEDIUMDASHED, ; BORDER_STYLE_MEDIUM, BORDER_STYLE_THICK, BORDER_STYLE_DOUBLE) RETURN False ENDIF RETURN True ENDPROC PROCEDURE mergecells && Merges cells together LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol LOCAL lnRow, lnCol, lcCellValue, lnStringIndex, lcDataType, lcCellFormula, llReturn IF PCOUNT() < 6 RETURN False ENDIF IF this.GetSheetRecord(tnWB, tnSheet) IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnBegRow)+BINTOC(tnBegCol), "xl_mergecells", "mergecell") REPLACE xl_mergecells.endrow WITH tnEndRow, ; xl_mergecells.endcol WITH tnEndCol IN xl_mergecells ELSE *-* Check if a cell being merged is already in a merge group SELECT xl_mergecells LOCATE FOR workbook = tnWB .AND. sheet = tnSheet .AND. BETWEEN(tnBegRow, begrow, endrow) .AND. BETWEEN(tnBegCol, begcol, endcol) .AND. !DELETED() IF FOUND() llReturn = False ELSE LOCATE FOR workbook = tnWB .AND. sheet = tnSheet .AND. BETWEEN(tnEndRow, begrow, endrow) .AND. BETWEEN(tnEndCol, begcol, endcol) .AND. !DELETED() IF FOUND() llReturn = False ELSE *-* Add merged cells INSERT INTO xl_mergecells (workbook, sheet, begrow, begcol, endrow, endcol) ; VALUES (tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol) *-* Get upper left most cell value -> will be value of the merged cells (clear all other cell values) SELECT xl_cells lcCellValue = .NULL. FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF this.GetCellRecord(tnWB, tnSheet, lnRow, lnCol) .AND. !EMPTY(xl_cells.cellvalue) IF ISNULL(lcCellValue) .AND. !xl_cells.celldeleted lcDataType = xl_cells.datatype lcCellValue = xl_cells.cellvalue lcCellFormula = xl_cells.cellformula lnStringIndex = xl_cells.stringid ENDIF REPLACE xl_cells.cellvalue WITH "", ; xl_cells.cellformula WITH "", ; xl_cells.stringid WITH 0, ; xl_cells.datatype WITH "" IN xl_cells ENDIF ENDFOR ENDFOR IF !ISNULL(lcCellValue) IF this.GetCellRecord(tnWB, tnSheet, tnBegRow, tnBegCol) REPLACE xl_cells.cellvalue WITH lcCellValue, ; xl_cells.cellformula WITH lcCellFormula, ; xl_cells.stringid WITH lnStringIndex, ; xl_cells.datatype WITH lcDataType, ; xl_cells.celldeleted WITH False IN xl_cells ENDIF ENDIF *-* If the tnEndCol cell is not a cell already in the row then add the cell to the cursor for the max cells by row determination * SELECT xl_cells * FOR lnRow=tnBegRow TO tnEndRow * LOCATE FOR workbook = tnWB .AND. sheet = tnSheet .AND. cellrow = lnRow .AND. cellcol >= tnEndCol .AND. !DELETED() * IF !FOUND() * INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, numdec, celldeleted) ; * VALUES (tnWB, tnSheet, lnRow, tnEndCol, DATA_TYPE_NONE, 0, -1, False) * ENDIF * ENDFOR llReturn = True ENDIF ENDIF ENDIF FOR lnRow=tnBegRow TO tnEndRow this.SetRowMaxColumn(tnWB, tnSheet, lnRow, tnEndCol) ENDFOR ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE ondestroy && Called by the Destroy() event - user implementation *-* *-* TODO: Add your code here *-* ENDPROC PROCEDURE oninit && User code for Init() Event *-* *-* TODO: Add your code here *-* ENDPROC PROCEDURE onshowerrormessage && Event for displaying an error message to the user LPARAMETERS tnErrorId, tcErrMessage *-* *-* TODO: Use BINDEVENTS to bind to this event and display a message to your users *-* ENDPROC PROCEDURE onshowstatusmessage && Event for displaying a wait message to the user LPARAMETERS tnMode, tnStage, tnTotStages *-* *-* TODO: Use BINDEVENTS to bind to this event and display a message to your users *-* *-* tnTotStages = total number of tnStages (only passed on first call) *-* *-* tnMode = 1; opening an xlsx file *-* tnStage = 0; start of open *-* tnStage = 1; reading shared strings XML *-* tnStage = 2; reading styles XML *-* tnStage = 3; reading relationships XML *-* tnStage = 4; reading sheets XML *-* tnStage = 5; reading named ranges *-* tnStage = 6; reading external references *-* tnStage = -1; end of open *-* *-* tnMode = 2; saving an xlsx file *-* tnStage = 0; start of save *-* tnStage = 1; indicates saving supporting XMLs *-* tnStage = 2; indicates saving strings XML *-* tnStage = 3; indicates saving styles XML *-* tnStage = 4; indicates saving workbook *-* tnStage = 5; indicates saving relationship XML *-* tnStage = 6+; indicates saving sheets *-* tnStage = -1; end of close *-* *-* tnMode = 3; saving an xlsx file *-* tnStage = 0; start of write of data to cell values *-* tnStage = 1-n; indicates saving cell values *-* tnStage = -1; write of data *-* ENDPROC PROCEDURE opencreatedxlsxfile && Opens the XLSX file via Win32 API default program LPARAMETERS txWB LOCAL lcFileName DO CASE CASE PCOUNT() = 0 RETURN False CASE VARTYPE(txWB) = "N" lcFileName = this.GetWorkbookFileName(txWB) IF EMPTY(lcFileName) .OR. !FILE(lcFileName) RETURN False ENDIF CASE VARTYPE(txWB) = "C" IF FILE(txWB) lcFileName = txWB ELSE RETURN False ENDIF OTHERWISE RETURN False ENDCASE TRY apiShellExecute(0, "Open", lcFileName, "", "", 5) CATCH TO loException RAISEEVENT(this, "OnShowErrorMessage", 99, "Failure to open file: " + loException.Message) ENDTRY ENDPROC PROCEDURE openxlsxworkbook && Opens the passed Xlsx workbook and loads the internal cursors with the content LPARAMETERS tcFileName, tlForceTextFormat LOCAL lnWB, lcBaseName, lcTempPath, lcZipName, loShell, lnCnt, lnCntTot, lcRelationsXml, lnNode LOCAL lnRelId, lcRelType, lcTarget, lcWbXmlPath, lcRelation, lcWorkbook, lcSheet, lcShName, lnShRId, lcShFile LOCAL loException, loFS, lcDefinedNames, lcDefinedName, lcRName, lcComment, lnRangeId, lcRange, lnNdx LOCAL lnBegRow, lnBegCol, lnEndRow, lnEndCol, lcExternalRefs, lnExRId, lcExtRef, lcCellRange, lcBegRange LOCAL lcEndRange, loDir, lnLastRelId, lcSheets, lcRelationships, lcShState LOCAL ARRAY laTemp[1] DO CASE CASE PCOUNT() = 0 this.ErrorLevelId = 1 RAISEEVENT(this, "OnShowErrorMessage", 1, "Invalid call to OpenXlsxWorkbook() method; must include file name to open") CASE PCOUNT() = 1 tlForceTextFormat = False ENDCASE lnWB = 0 IF ADIR(laTemp, tcFileName) > 0 *-* Open the Workbook as an archive (zip) file and extract contents TRY lcBaseName = SYS(2015) lcTempPath = ADDBS(SYS(2023)) + lcBaseName lcZipName = lcTempPath + ".zip" COPY FILE (tcFileName) TO (lcZipName) loShell = CREATEOBJECT("shell.application") MKDIR (lcTempPath) loShell.NameSpace(lcTempPath).CopyHere(loShell.NameSpace(lcZipName).Items, FOF_SILENT) lnCnt = 0 lnCntTot = loShell.NameSpace(lcZipName).Items.Count DO WHILE loShell.NameSpace(lcTempPath).Items.Count != lnCntTot lnCnt = lnCnt + 1 apiSleep(100) IF lnCnt > lnCntTot SET STEP ON ENDIF ENDDO ERASE (lcZipName) CATCH TO loException SET STEP ON this.ErrorLevelId = 2 RAISEEVENT(this, "OnShowErrorMessage", 2, loException.Message) lnWB = .NULL. ENDTRY IF ISNULL(lnWB) RETURN 0 ENDIF *-* Add to the workbook table lnWB = this.CreateWorkbookEx(tcFileName) IF lnWB > 0 *-* Verify all required XML files are present lcWbXmlPath = ADDBS(lcTempPath) IF ADIR(laTemp, lcWbXmlPath + "xl\workbook.xml") = 0 this.ErrorLevelId = 3 RAISEEVENT(this, "OnShowErrorMessage", 3, "Invalid XLSX file - missing workbook.xml") this.DeleteWorkbook(lnWB) RETURN 0 ENDIF IF ADIR(laTemp, lcWbXmlPath + "xl\_rels\workbook.xml.rels") = 0 this.ErrorLevelId = 4 RAISEEVENT(this, "OnShowErrorMessage", 4, "Invalid XLSX file - missing workbook.xml.rels") this.DeleteWorkbook(lnWB) RETURN 0 ENDIF IF ADIR(laTemp, lcWbXmlPath + "xl\styles.xml") = 0 this.ErrorLevelId = 5 RAISEEVENT(this, "OnShowErrorMessage", 5, "Invalid XLSX file - missing styles.xml") this.DeleteWorkbook(lnWB) RETURN 0 ENDIF *-* Process the workbook RAISEEVENT(this, "OnShowStatusMessage", 1, 1, 6) TRY *-* Get the shared strings if present IF ADIR(laTemp, lcWbXmlPath + "xl\sharedStrings.xml") > 0 IF !this.ReadSharedStringsXML(lcWbXmlPath, lnWB) this.ErrorLevelId = 7 RAISEEVENT(this, "OnShowErrorMessage", 7, "Invalid XLSX file - error during shared string loading") THROW ENDIF ENDIF *-* Get the cell formatting styles this.ReadStylesXML(lcWbXmlPath, lnWB) *-* Get the defined relationship files for this workbook RAISEEVENT(this, "OnShowStatusMessage", 1, 3) lcRelationsXml = FILETOSTR(lcWbXmlPath + "xl\_rels\workbook.xml.rels") lcRelationships = this.GetNodeElement(lcRelationsXml, 'Relationships', 1, False, 1) lnNode = 1 lnLastRelId = 0 lcRelation = this.GetNodeElement(lcRelationships, 'Relationship', lnNode) DO WHILE !EMPTY(lcRelation) lnRelId = CAST(SUBSTR(this.GetNodeAttributeValue(lcRelation, "Id"), 4) AS I) lcTarget = this.GetNodeAttributeValue(lcRelation, "Target") lcRelType = this.GetNodeAttributeValue(lcRelation, "Type") lcRelType = SUBSTR(lcRelType, RATC("/", lcRelType)+1) IF lcRelType != "theme" INSERT INTO xl_relationships (workbook, relid, reltype, target) VALUES (lnWB, lnRelId, lcRelType, lcTarget) IF lnRelId > lnLastRelId lnLastRelId = lnRelId ENDIF ENDIF lnNode = lnNode + 1 lcRelation = this.GetNodeElement(lcRelationships, 'Relationship', lnNode) ENDDO this.SetLastId(lnWB, lnLastRelId, "xl_relationships") *-* Get the sheets RAISEEVENT(this, "OnShowStatusMessage", 1, 4) lcWorkbook = FILETOSTR(lcWbXmlPath + "xl\workbook.xml") lcSheets = this.GetNodeElement(lcWorkbook, 'sheets', 1, False, 1) lnNode = 1 lcSheet = this.GetNodeElement(lcSheets, 'sheet', lnNode) DO WHILE !EMPTY(lcSheet) lcShName = this.GetNodeAttributeValue(lcSheet, "name") lnShRId = CAST(SUBSTR(this.GetNodeAttributeValue(lcSheet, "r:id"), 4) AS I) lcShFile = lcWbXmlPath + "xl\" + this.GetRelationshipFileName(lnWB, lnShRId) lcShState = this.GetNodeAttributeValue(lcSheet, "state") DO CASE CASE lcShState = "visible" lnShState = VISIBLE_SHEET_STATE CASE lcShState = "hidden" lnShState = HIDDEN_SHEET_STATE CASE lcShState = "veryHidden" lnShState = VERYHIDDEN_SHEET_STATE OTHERWISE lnShState = VISIBLE_SHEET_STATE ENDCASE IF ADIR(laTemp, lcShFile) = 0 .OR. !this.ReadSheetXML(lcShFile, lnWB, lnNode, lcShName, lnShState, tlForceTextFormat) this.ErrorLevelId = 8 RAISEEVENT(this, "OnShowErrorMessage", 8, "Invalid XLSX file - missing sheet or invalid sheet: " + lcShFile) this.DeleteWorkbook(lnWB) THROW ENDIF IF SEEK(BINTOC(lnWB)+BINTOC(lnShRId), "xl_relationships", "relid") REPLACE xl_relationships.sheet WITH lnNode IN xl_relationships ELSE SET STEP ON ENDIF lnNode = lnNode + 1 lcSheet = this.GetNodeElement(lcSheets, 'sheet', lnNode) ENDDO this.SetLastId(lnWB, lnNode-1, "xl_sheets") *-* Get the defined name ranges RAISEEVENT(this, "OnShowStatusMessage", 1, 5) lcDefinedNames = this.GetNodeElement(lcWorkbook, 'definedNames', 1) IF !EMPTY(lcDefinedNames) lnNode = 1 lcDefinedName = this.GetNodeElement(lcDefinedNames, 'definedName', lnNode) DO WHILE !EMPTY(lcDefinedName) lcRange = this.GetNodeElementValue(lcDefinedName) IF !EMPTY(lcRange) lnNdx = ATC("!", lcRange) lcShName = LEFT(lcRange, lnNdx-1) IF !EMPTY(lcShName) lcShName = CHRTRAN(lcShName, "'", "") IF SEEK(BINTOC(lnWB)+UPPER(PADR(lcShName, LEN(xl_sheets.shname))), "xl_sheets", "shname") lcRName = this.GetNodeAttributeValue(lcDefinedName, "name") lcComment = this.GetNodeAttributeValue(lcDefinedName, "comment") lnRangeId = CAST(this.GetNodeAttributeValue(lcDefinedName, "localSheetId") AS I) lcCellRange = SUBSTR(lcRange, lnNdx+1) lcCellRange = CHRTRAN(lcCellRange, "$", "") lcBegRange = GETWORDNUM(lcCellRange, 1, ":") lcEndRange = GETWORDNUM(lcCellRange, 2, ":") lnNdx = this.GetAlphaNumericSplit(lcBegRange) DO CASE CASE lnNdx = 0 && Column only range lnBegCol = this.ColumnAsciiToIndex(lcBegRange) lnBegRow = 0 CASE lnNdx = 1 && Row only range lnBegCol = 0 lnBegRow = CAST(lcBegRange AS I) OTHERWISE lnBegCol = this.ColumnAsciiToIndex(LEFT(lcBegRange, lnNdx-1)) lnBegRow = CAST(SUBSTR(lcBegRange, lnNdx) AS I) ENDCASE lnNdx = this.GetAlphaNumericSplit(lcEndRange) DO CASE CASE lnNdx = 0 && Column only range lnEndCol = this.ColumnAsciiToIndex(lcEndRange) lnEndRow = 0 CASE lnNdx = 1 && Row only range lnEndCol = 0 lnEndRow = CAST(lcEndRange AS I) OTHERWISE lnEndCol = this.ColumnAsciiToIndex(LEFT(lcEndRange, lnNdx-1)) lnEndRow = CAST(SUBSTR(lcEndRange, lnNdx) AS I) ENDCASE INSERT INTO xl_namerange (workbook, sheet, rname, scope, comment, begrow, begcol, endrow, endcol) ; VALUES (lnWB, xl_sheets.sheet, lcRName, lnRangeId, lcComment, lnBegRow, lnBegCol, lnEndRow, lnEndCol) ENDIF ENDIF ENDIF lnNode = lnNode + 1 lcDefinedName = this.GetNodeElement(lcDefinedNames, 'definedName', lnNode) ENDDO ENDIF *-* Get the external references RAISEEVENT(this, "OnShowStatusMessage", 1, 6) * lcExternalRefs = this.GetNodeElement(lcWorkbook, 'externalReferences', 1) * IF !EMPTY(lcExternalRefs) * lnNode = 1 * lcExtRef = this.GetNodeElement(lcExternalRefs, 'externalReference', lnNode) * DO WHILE !EMPTY(lcExtRef) * lnExRId = CAST(SUBSTR(this.GetNodeAttributeValue(lcExtRef, "r:id"), 4) AS I) * lcFile = lcWbXmlPath + "xl\" + this.GetRelationshipFileName(lnWB, lnExRId) * this.ReadExternalRefXML(lnWB, lcFile, lnExRId) * * lnNode = lnNode + 1 * lcExtRef = this.GetNodeElement(lcExternalRefs, 'externalReference', lnNode) * ENDDO * ENDIF CATCH TO loException SET STEP ON this.ErrorLevelId = 9 RAISEEVENT(this, "OnShowErrorMessage", 9, "Invalid XLSX file - error reading data; " + loException.Message) this.DeleteWorkbook(lnWB) lnWB = 0 FINALLY TRY loFS = CREATEOBJECT("Scripting.FileSystemObject") loDir = loFS.GetFolder(lcTempPath) loDir.Delete() CATCH TO loException SET STEP ON ENDTRY RAISEEVENT(this, "OnShowStatusMessage", 1, -1) ENDTRY IF this.Debug this.DebugCursorsToFile("Extract") ENDIF ENDIF ENDIF RETURN lnWB ENDPROC PROCEDURE parsestring && Parses a string based on a specified delimiter LPARAMETERS tcText, tnPos, tcDelimiter LOCAL lcWord, lnCnt, lnBeg, lnEnd lnCnt = OCCURS(tcDelimiter, tcText) + 1 IF tnPos <= lnCnt DO CASE CASE lnCnt = 0 lcWord = tcText CASE tnPos = 1 lcWord = LEFT(tcText, ATC(tcDelimiter, tcText)-1) CASE tnPos = lnCnt lcWord = SUBSTR(tcText, RATC(tcDelimiter, tcText)+1) OTHERWISE lnBeg = ATC(tcDelimiter, tcText, tnPos-1) + 1 lnEnd = ATC(tcDelimiter, tcText, tnPos) lcWord = SUBSTR(tcText, lnBeg, lnEnd-lnBeg) ENDCASE RETURN lcWord ELSE RETURN "" ENDIF ENDPROC PROTECTED PROCEDURE readcellvalueformat && Reads the cell value and format for a sheet LPARAMETERS tnWB, tcColumn, tnCellCol LOCAL lcCellType, lnNode, lcBaseName, lcFormatCode, lnNdx, loCellFormat, lcWholeNbr, lcDecNbr LOCAL lcPosFormat, lcNegFormat, lcZerFormat, lcInLineTxt loCellFormat = CREATEOBJECT("Empty") ADDPROPERTY(loCellFormat, "CellVal", "") ADDPROPERTY(loCellFormat, "DataType", DATA_TYPE_NONE) ADDPROPERTY(loCellFormat, "Formula", "") ADDPROPERTY(loCellFormat, "StringNdx", 0) ADDPROPERTY(loCellFormat, "CellXfsId", 0) lcCellType = this.GetNodeAttributeValue(tcColumn, "t") FOR lnChild=1 TO this.GetChildNodeCount(tcColumn) lcChild = this.GetChildNodeElement(tcColumn, lnChild) DO CASE CASE lcChild = " 0 lnNdx = ATC(".", loCellFormat.CellVal) lcWholeNbr = LEFT(loCellFormat.CellVal, lnNdx-1) lcDecNbr = SUBSTR(loCellFormat.CellVal, lnNdx+1) IF LEN(lcDecNbr) > 0 loCellFormat.CellVal = lcWholeNbr + "." + PADR(lcDecNbr, 17, "0") loCellFormat.DataType = DATA_TYPE_DATETIME ELSE loCellFormat.CellVal = lcWholeNbr loCellFormat.DataType = DATA_TYPE_DATE ENDIF ENDCASE CASE INLIST(xl_cellxfs.numFmtId, 18, 19, 20, 21, 45, 46) && Time format DO CASE CASE ATC("E-", loCellFormat.CellVal) > 0 loCellFormat.CellVal = PADR(TRANSFORM(EVAL(loCellFormat.CellVal)), 19, "0") loCellFormat.DataType = DATA_TYPE_TIME CASE ATC("E", loCellFormat.CellVal) > 0 loCellFormat.CellVal = TRANSFORM(EVAL(loCellFormat.CellVal)) lnNdx = ATC(".", loCellFormat.CellVal) lcWholeNbr = LEFT(loCellFormat.CellVal, lnNdx-1) lcDecNbr = SUBSTR(loCellFormat.CellVal, lnNdx+1) loCellFormat.CellVal = lcWholeNbr + "." + PADR(lcDecNbr, 17, "0") loCellFormat.DataType = DATA_TYPE_DATETIME CASE LEFT(loCellFormat.CellVal, 2) = "0." lcDecNbr = SUBSTR(loCellFormat.CellVal, 3) loCellFormat.CellVal = "0." + PADR(lcDecNbr, 17, "0") loCellFormat.DataType = DATA_TYPE_TIME OTHERWISE lnNdx = ATC(".", loCellFormat.CellVal) lcWholeNbr = LEFT(loCellFormat.CellVal, lnNdx-1) lcDecNbr = SUBSTR(loCellFormat.CellVal, lnNdx+1) loCellFormat.CellVal = lcWholeNbr + "." + PADR(lcDecNbr, 17, "0") loCellFormat.DataType = DATA_TYPE_DATETIME ENDCASE CASE INLIST(xl_cellxfs.numFmtId, 22, 29, 30, 31, 32, 33, 34) && Date-time format lnNdx = ATC(".", loCellFormat.CellVal) lcWholeNbr = IIF(lnNdx=0, loCellFormat.CellVal, LEFT(loCellFormat.CellVal, lnNdx-1)) && Bug fix provide by Dan Goodwin from VFPx lcDecNbr = IIF(lnNdx=0, "", SUBSTR(loCellFormat.CellVal, lnNdx+1)) && Bug fix provide by Dan Goodwin from VFPx loCellFormat.CellVal = lcWholeNbr + "." + PADR(lcDecNbr, 17, "0") loCellFormat.DataType = DATA_TYPE_DATETIME CASE xl_cellxfs.numFmtId = 49 && Numeric formatted as text loCellFormat.StringNdx = this.AddStringValue(tnWB, loCellFormat.CellVal, False) loCellFormat.CellVal = "StringValue" loCellFormat.DataType = DATA_TYPE_CHAR CASE SEEK(BINTOC(tnWB)+BINTOC(xl_cellxfs.numFmtId), "xl_numfmts", "id") && Determine based on custom format lcFormatCode = ALLTRIM(xl_numfmts.formatcode) DO CASE CASE ATC("h:m", lcFormatCode) > 0 .OR. ATC("m:s", lcFormatCode) > 0 .OR. ATC("AM/PM", lcFormatCode) > 0 .OR. ATC("A/P", lcFormatCode) > 0 loCellFormat.DataType = DATA_TYPE_DATETIME CASE ATC("yy", lcFormatCode) > 0 .OR. ATC("d\-m", lcFormatCode) > 0 loCellFormat.DataType = DATA_TYPE_DATE OTHERWISE lnNdx = ATC(".", lcFormatCode) IF lnNdx > 0 loCellFormat.DataType = DATA_TYPE_FLOAT lnNdx = lnNdx + 1 DO WHILE lnNdx < LEN(lcFormatCode) IF SUBSTR(lcFormatCode, lnNdx, 1) != "0" EXIT ENDIF lnNdx = lnNdx + 1 ENDDO ELSE loCellFormat.DataType = DATA_TYPE_INT ENDIF ENDCASE OTHERWISE DO CASE CASE ISNULL(loCellFormat.CellVal) .OR. EMPTY(loCellFormat.CellVal) loCellFormat.DataType = DATA_TYPE_NONE CASE ATC(".", loCellFormat.CellVal) > 0 loCellFormat.DataType = DATA_TYPE_FLOAT OTHERWISE loCellFormat.DataType = DATA_TYPE_INT ENDCASE ENDCASE ELSE DO CASE CASE ISNULL(loCellFormat.CellVal) .OR. EMPTY(loCellFormat.CellVal) loCellFormat.CellVal = "" loCellFormat.DataType = DATA_TYPE_NONE CASE ATC(".", loCellFormat.CellVal) > 0 loCellFormat.DataType = DATA_TYPE_FLOAT OTHERWISE loCellFormat.DataType = DATA_TYPE_INT ENDCASE ENDIF ENDCASE RETURN loCellFormat ENDPROC PROTECTED PROCEDURE readexternalrefxml && Reads the External References file LPARAMETERS tnWB, tcFileName, tnRelId LOCAL lcExternalLink, lcSheetNames, lnNode, lcSheetName, lcShName *-* Open the external file for processing lcExternalLink = FILETOSTR(tcFileName) *-* Get the sheet names lcSheetNames = this.GetNodeElement(lcExternalLink, 'sheetNames', 1) IF !EMPTY(lcSheetNames) lnNode = 1 lcSheetName = this.GetNodeElement(lcSheetNames, 'sheetName', lnNode) DO WHILE !EMPTY(lcSheetName) lcShName = this.GetNodeAttributeValue(lcSheetName, "val") INSERT INTO xl_extsheets (workbook, extid, relid, sheetname) VALUES (tnWB, lnNode, tnRelId, lcShName) lnNode = lnNode + 1 lcSheetName = this.GetNodeElement(lcSheetNames, 'sheetName', lnNode) ENDDO *-* Get each external sheet detail lnNode = 1 lcSheetData = this.GetNodeElement(lcExternalLink, 'sheetData', lnNode) DO WHILE !EMPTY(lcSheetData) lnRow = 1 lcRowData = this.GetNodeElement(lcSheetData, 'row', lnRow) DO WHILE !EMPTY(lcRowData) ENDDO lnNode = lnNode + 1 lcSheetData = this.GetNodeElement(lcExternalLink, 'sheetData', lnNode) ENDDO ENDIF ENDPROC PROTECTED PROCEDURE readsharedstringsxml && Reads the sharedstrings.xml for opening workbooks LPARAMETERS tcFilePath, tnWB LOCAL lcStrings, lcString, lnNode, lcRichTextRun, lcText, lnIndex, llFBold, llFItalic, loException, lcT LOCAL lnFColor, lcFName, lnFSize, lcULine, llStrkThr, lcFVPos, lnTheme, lnTint, lnIndexed, lcRunPrp LOCAL lnR, lcRText, lcRunProp, lcColor, llPrsvSp, llFormatted, llSuccess, lhFile, lcSharedStringFile, lnSize LOCAL lcStringXml, lcCheckSum RAISEEVENT(this, "OnShowStatusMessage", 1, 1) TRY lcSharedStringFile = ADDBS(tcFilePath) + "xl\sharedStrings.xml" lcStrings = FILETOSTR(lcSharedStringFile) IF this.CodePage = 0 lcStrings = STRCONV(lcStrings, 11) ELSE lcStrings = STRCONV(lcStrings, 11, this.CodePage, 1) ENDIF lnNode = 1 lcString = this.GetNodeElement(lcStrings, 'si', lnNode) DO WHILE !EMPTY(lcString) lnR = 1 lcRichTextRun = this.GetNodeElement(lcString, 'r', lnR, True) IF EMPTY(lcRichTextRun) llFormatted = False lcT = this.GetNodeElement(lcString, 't', 1) lcText = this.GetNodeElementValue(lcT) llPrsvSp = IIF(EMPTY(this.GetNodeAttributeValue(lcT, "xml:space")), False, True) IF llPrsvSp lcRText = CHRTRAN(lcText, CHR(32), CHR(160)) ENDIF ELSE llFormatted = True lcText = "" lnIndex = 0 DO WHILE !EMPTY(lcRichTextRun) lnIndex = lnIndex + 1 lcT = this.GetNodeElement(lcRichTextRun, 't', 1) llPrsvSp = IIF(EMPTY(this.GetNodeAttributeValue(lcT, "xml:space")), False, True) lcRText = this.GetNodeElementValue(lcT) lcText = lcText + lcRText lcRunProp = this.GetNodeElement(lcRichTextRun, 'rPr', 1, True) llFBold = IIF(ATC("", lcRunProp)>0, True, False) llFItalic = IIF(ATC("", lcRunProp)>0, True, False) llStrkthr = IIF(ATC("", lcRunProp)>0, True, False) IF ATC("", lcRunProp) > 0 lcULine = UNDERLINE_SINGLE ELSE lcULine = this.GetNodeAttributeValue(this.GetNodeElement(lcRunProp, 'u', 1), "val") lcULine = IIF(EMPTY(lcULine), UNDERLINE_NONE, lcULine) ENDIF lnFSize = CAST(this.GetNodeAttributeValue(this.GetNodeElement(lcRunProp, 'sz', 1), "val") AS I) lcFName = this.GetNodeAttributeValue(this.GetNodeElement(lcRunProp, 'rFont', 1), "val") lcFVPos = this.GetNodeAttributeValue(this.GetNodeElement(lcRunProp, 'vertAlign', 1), "val") lcColor = this.GetNodeElement(lcRunProp, 'color', 1) lnFColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnIndexed = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) IF llPrsvSp lcRText = CHRTRAN(lcRText, CHR(32), CHR(160)) ENDIF INSERT INTO xl_strformat (workbook, id, index, stringxml, stringval, fbold, fitalic, fcolor, fname, fsize, uline, strkthr, fvpos, theme, tint, indexed, presvspace) ; VALUES (tnWB, lnNode-1, lnIndex, lcRText, this.GetStringXML(lcRText), llFBold, llFItalic, lnFColor, lcFName, lnFSize, lcULine, llStrkThr, ; lcFVPos, lnTheme, lnTint, lnIndexed, llPrsvSp) lnR = lnR + 1 lcRichTextRun = this.GetNodeElement(lcString, 'r', lnR, True) ENDDO llPrsvSp = False ENDIF lcStringXml = this.GetXMLString(lcText) lcCheckSum = this.GetCheckSum(lcText) INSERT INTO xl_strings (id, workbook, checksum, stringxml, stringval, presvspace, formatted) ; VALUES (lnNode-1, tnWB, lcCheckSum, lcText, lcStringXml, llPrsvSp, llFormatted) lnNode = lnNode + 1 lcString = this.GetNodeElement(lcStrings, 'si', lnNode) ENDDO this.SetLastId(tnWB, lnNode-2, "xl_strings") && Decrement by 2 to account for empty string not assigned llSuccess = True CATCH TO loException SET STEP ON llSuccess = False ENDTRY RETURN llSuccess ENDPROC PROTECTED PROCEDURE readsheetxml && Reads the sheet.xml for opening a workbook LPARAMETERS tcShFile, tnWB, tnSheet, tcShName, tnShState, tlForceTextFormat LOCAL lcSheet, lcSheetViews, lcSheetView, lcPane, lcMargin, lnXSplit, lnYSplit, lnLeft, lcDimen, lnScale, lnFitToWidth, lnFitToHeight LOCAL lnRight, lnTop, lnBottom, lnHeader, lnFooter, lcPageSetup, lnOrientation, lnPaperSize, lnWidth, lnHeight, lnNode, lcMergeCells LOCAL lnCnt, lcMergeCell, lcCellRef, lnBegCol, lnBegRow, lnEndCol, lnEndRow, lcTemp, lnNdx, lcSheetData LOCAL lcRow, lnRowHt, lnCellRow, lnCellCol, lnCol, loCell, lnTabColNdx, lcTabColRgb, lcTabColor, lcSheetPr LOCAL lcValidations, lnValidType, lcValidation, lnValidStyle, lnOperator, lcErrMsg, lcErrTitle, lcPrompt, lcFormula1 LOCAL lcFormula2, llAllowBlank, llShowInputMsg, llShowErrMsg, llFormula, llCustHt, lcValidType, lcValidStyle LOCAL lcValidSqRef, lnIndex *-* Open the sheet for processing lcSheet = FILETOSTR(tcShFile) IF this.CodePage = 0 lcSheet = STRCONV(lcSheet, 11) ELSE lcSheet = STRCONV(lcSheet, 11, this.CodePage, 1) ENDIF *-* Get the freeze rows/columns settings lcSheetViews = this.GetNodeElement(lcSheet, 'sheetViews', 1, True) lcSheetView = this.GetNodeElement(lcSheetViews, 'sheetView', 1) lcPane = this.GetNodeElement(lcSheetView, 'pane', 1) lnXSplit = CAST(this.GetNodeAttributeValue(lcPane, "xSplit") AS I) lnYSplit = CAST(this.GetNodeAttributeValue(lcPane, "ySplit") AS I) *-* Get the tab color settings lcSheetPr = this.GetNodeElement(lcSheet, 'sheetPr', 1) IF EMPTY(lcSheetPr) lnTabColNdx = 0 lcTabColRgb = "" ELSE lcTabColor = this.GetNodeElement(lcSheetPr, 'tabColor', 1) lnTabColNdx = CAST(this.GetNodeAttributeValue(lcTabColor, "indexed") AS I) lcTabColRgb = this.GetNodeAttributeValue(lcTabColor, "rgb") ENDIF *-* Get the worksheet margins lcMargin = this.GetNodeElement(lcSheet, 'pageMargins', 1) lnLeft = CAST(this.GetNodeAttributeValue(lcMargin, "left") AS N(6,3)) lnLeft = IIF(lnLeft = 0.000, 0.75, lnLeft) lnRight = CAST(this.GetNodeAttributeValue(lcMargin, "right") AS N(6,3)) lnRight = IIF(lnRight = 0.000, 0.75, lnRight) lnTop = CAST(this.GetNodeAttributeValue(lcMargin, "top") AS N(6,3)) lnTop = IIF(lnTop = 0.000, 0.75, lnTop) lnBottom = CAST(this.GetNodeAttributeValue(lcMargin, "bottom") AS N(6,3)) lnBottom = IIF(lnBottom = 0.000, 0.75, lnBottom) lnFooter = CAST(this.GetNodeAttributeValue(lcMargin, "footer") AS N(6,3)) lnFooter = IIF(lnFooter = 0.000, 0.30, lnFooter) lnHeader = CAST(this.GetNodeAttributeValue(lcMargin, "header") AS N(6,3)) lnHeader = IIF(lnHeader = 0.000, 0.30, lnHeader) *-* Get the page setup lcPageSetup = this.GetNodeElement(lcSheet, 'pageMargins', 1) lnOrientation = IIF(this.GetNodeAttributeValue(lcPageSetup, "orientation")='portrait', PORTRAIT_PRINT_ORIENTATION, LANDSCAPE_PRINT_ORIENTATION) lnPaperSize = CAST(this.GetNodeAttributeValue(lcPageSetup, "paperSize") AS I) lnPaperSize = IIF(lnPaperSize=0, PAPERSIZE_LTR, lnPaperSize) lnWidth = CAST(this.GetNodeAttributeValue(lcPageSetup, "paperWidth") AS I) lnHeight = CAST(this.GetNodeAttributeValue(lcPageSetup, "paperHeight") AS I) lcDimen = RIGHT(this.GetNodeAttributeValue(lcPageSetup, "paperHeight"), 2) lnScale = CAST(this.GetNodeAttributeValue(lcPageSetup, "scale") AS I) lnScale = IIF(lnScale=0, 100, lnScale) lnFitToWidth = CAST(this.GetNodeAttributeValue(lcPageSetup, "fitToWidth") AS I) lnFitToHeight = CAST(this.GetNodeAttributeValue(lcPageSetup, "fitToHeight") AS I) *-* Save the worksheet to the cursor INSERT INTO xl_sheets (workbook, sheet, shname, state, mleft, mright, mtop, mbot, mheader, mfooter, shdeleted, xsplit, ysplit, prnorient, ; papersize, paperwidth, paperheight, paperdimen, scale, fittowidth, fittoheight, tabcolorndx, tabcolorrgb) ; VALUES (tnWB, tnSheet, tcShName, tnShState, lnLeft, lnRight, lnTop, lnBottom, lnHeader, lnFooter, False, lnXSplit, lnYSplit, lnOrientation, ; lnPaperSize, lnWidth, lnHeight, lcDimen, lnScale, lnFitToWidth, lnFitToHeight, lnTabColNdx, lcTabColRgb) *-* Get the defined column widths lcCols = this.GetNodeElement(lcSheet, 'cols', 1, True) lnNode = 1 lcCol = this.GetNodeElement(lcCols, 'col', lnNode) DO WHILE !EMPTY(lcCol) lnMinCol = CAST(this.GetNodeAttributeValue(lcCol, "min") AS I) lnMaxCol = CAST(this.GetNodeAttributeValue(lcCol, "max") AS I) lnWidth = CAST(this.GetNodeAttributeValue(lcCol, "width") AS N(16,9)) - 0.71093750 FOR lnCol=lnMinCol TO lnMaxCol INSERT INTO xl_colwidths (workbook, sheet, COLUMN, width) VALUES (tnWB, tnSheet, lnCol, lnWidth) ENDFOR lnNode = lnNode + 1 lcCol = this.GetNodeElement(lcCols, 'col', lnNode) ENDDO *-* Get the defined merged cells lcMergeCells = this.GetNodeElement(lcSheet, 'mergeCells', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcMergeCells, "count") AS I) FOR lnNode=1 TO lnCnt lcMergeCell = this.GetNodeElement(lcMergeCells, 'mergeCell', lnNode) IF EMPTY(lcMergeCell) SET STEP ON LOOP ENDIF lcCellRef = this.GetNodeAttributeValue(lcMergeCell, "ref") lnBegCol = 0 lnBegRow = 0 lnEndCol = 0 lnEndRow = 0 lcTemp = GETWORDNUM(lcCellRef, 1, ":") lnNdx = 0 DO WHILE lnNdx < LEN(lcTemp) lnNdx = lnNdx + 1 IF ISDIGIT(SUBSTR(lcTemp, lnNdx, 1)) lnBegCol = this.ColumnAsciiToIndex(LEFT(lcTemp, lnNdx-1)) lnBegRow = INT(VAL(SUBSTR(lcTemp, lnNdx))) EXIT ENDIF ENDDO IF lnBegCol > 0 lcTemp = GETWORDNUM(lcCellRef, 2, ":") lnNdx = 0 DO WHILE lnNdx < LEN(lcTemp) lnNdx = lnNdx + 1 IF ISDIGIT(SUBSTR(lcTemp, lnNdx, 1)) lnEndCol = this.ColumnAsciiToIndex(LEFT(lcTemp, lnNdx-1)) lnEndRow = INT(VAL(SUBSTR(lcTemp, lnNdx))) EXIT ENDIF ENDDO IF lnEndCol > 0 INSERT INTO xl_mergecells (workbook, sheet, begrow, begcol, endrow, endcol) ; VALUES (tnWB, tnSheet, lnBegRow, lnBegCol, lnEndRow, lnEndCol) ENDIF ENDIF ENDFOR *-* Get the sheet cell values and formatting lcSheetData = this.GetNodeElement(lcSheet, 'sheetData', 1, True) lnNode = 1 lcRow = this.GetNodeElement(lcSheetData, 'row', lnNode) DO WHILE !EMPTY(lcRow) && Process each row in the sheet lnCellRow = CAST(this.GetNodeAttributeValue(lcRow, "r") AS I) lnRowHt = CAST(this.GetNodeAttributeValue(lcRow, "ht") AS N(14,7)) llCustHt = IIF(CAST(this.GetNodeAttributeValue(lcRow, "customHeight") AS I) = 1, True, False) IF llCustHt .OR. (lnRowHt > 0.00 .AND. lnRowHt != 30) INSERT INTO xl_rowheights (workbook, sheet, row, height) VALUES (tnWB, tnSheet, lnCellRow, lnRowHt) ENDIF lnCol = 1 lnCellCol = 1 lcColumn = this.GetNodeElement(lcRow, 'c', lnCol) DO WHILE !EMPTY(lcColumn) && Process each column in a row lnCellCol = this.ColumnAsciiToIndex(this.GetNodeAttributeValue(lcColumn, "r")) loCell = this.ReadCellValueFormat(tnWB, lcColumn, lnCellCol) IF tlForceTextFormat .AND. loCell.DataType != DATA_TYPE_CHAR loCell.DataType = DATA_TYPE_CHAR loCell.StringNdx = this.AddStringValue(tnWB, TRANSFORM(loCell.CellVal), False) loCell.CellVal = "StringValue" loCell.Formula = "" ENDIF INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, cellvalue, datatype, cellformula, stringid, cellxfs, celldeleted) ; VALUES (tnWB, tnSheet, lnCellRow, lnCellCol, loCell.CellVal, loCell.DataType, loCell.Formula, loCell.StringNdx, loCell.CellXfsId, False) lnCol = lnCol + 1 lcColumn = this.GetNodeElement(lcRow, 'c', lnCol) ENDDO INSERT INTO xl_rows (workbook, sheet, row, maxcol) VALUES (tnWB, tnSheet, lnCellRow, lnCellCol) lnNode = lnNode + 1 lcRow = this.GetNodeElement(lcSheet, 'row', lnNode) ENDDO *-* Get the validations lcValidations = this.GetNodeElement(lcSheet, 'dataValidations', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcValidations, "count") AS I) FOR lnNode=1 TO lnCnt lcValidation = this.GetNodeElement(lcValidations, 'dataValidation', lnNode) IF EMPTY(lcValidation) SET STEP ON LOOP ENDIF lcValidSqRef = this.GetNodeAttributeValue(lcValidation, "sqref") IF EMPTY(lcValidSqRef) SET STEP ON LOOP ENDIF lcValidType = this.GetNodeAttributeValue(lcValidation, "type") DO CASE CASE lcValidType = "none" lnValidType = NONE_VALID_TYPE CASE lcValidType = "whole" lnValidType = WHOLE_VALID_TYPE CASE lcValidType = "decimal" lnValidType = DECIMAL_VALID_TYPE CASE lcValidType = "list" lnValidType = LIST_VALID_TYPE CASE lcValidType = "date" lnValidType = DATE_VALID_TYPE CASE lcValidType = "time" lnValidType = TIME_VALID_TYPE CASE lcValidType = "textLength" lnValidType = TXTLEN_VALID_TYPE CASE lcValidType = "custom" lnValidType = CUSTOM_VALID_TYPE OTHERWISE lnValidType = NONE_VALID_TYPE ENDCASE lcValidStyle = this.GetNodeAttributeValue(lcValidation, "errorStyle") DO CASE CASE lcValidStyle = "stop" lnValidStyle = STOP_VALID_STYLE CASE lcValidStyle = "warning" lnValidStyle = WARN_VALID_STYLE CASE lcValidStyle = "information" lnValidStyle = INFO_VALID_STYLE OTHERWISE lnValidStyle = 0 ENDCASE lcOperator = this.GetNodeAttributeValue(lcValidation, "operator") DO CASE CASE lcOperator = "between" lnOperator = BETWEEN_VALID_OPER CASE lcOperator = "notBetween" lnOperator = NOTBETW_VALID_OPER CASE lcOperator = "equal" lnOperator = EQUAL_VALID_OPER CASE lcOperator = "notEqual" lnOperator = NOTEQUAL_VALID_OPER CASE lcOperator = "lessThan" lnOperator = LESSTHAN_VALID_OPER CASE lcOperator = "lessThanOrEqual" lnOperator = LESSOREQUAL_VALID_OPER CASE lcOperator = "greaterThan" lnOperator = GREATTHAN_VALID_OPER CASE lcOperator = "greaterThanOrEqual" lnOperator = GREATOREQUAL_VALID_OPER OTHERWISE lnOperator = 0 ENDCASE lcErrMsg = this.GetNodeAttributeValue(lcValidation, "error") lcErrTitle = this.GetNodeAttributeValue(lcValidation, "errorTitle") lcPrompt = this.GetNodeAttributeValue(lcValidation, "prompt") llAllowBlank = IIF(CAST(this.GetNodeAttributeValue(lcValidation, "allowBlank") AS I)=1, True, False) llShowInputMsg = IIF(CAST(this.GetNodeAttributeValue(lcValidation, "showInputMessage") AS I)=1, True, False) llShowErrMsg = IIF(CAST(this.GetNodeAttributeValue(lcValidation, "showErrorMessage") AS I)=1, True, False) lcFormula1 = this.GetNodeElementValue(this.GetNodeElement(lcValidation, 'formula1', 1, True)) lcFormula2 = this.GetNodeElementValue(this.GetNodeElement(lcValidation, 'formula2', 1, True)) IF LEFT(lcFormula1, 1) = '"' .OR. LEFT(lcFormula2, 1) = '"' lcFormula1 = ALLTRIM(lcFormula1, 1, '"') lcFormula2 = ALLTRIM(lcFormula2, 1, '"') llFormula = False ELSE llFormula = True ENDIF INSERT INTO xl_validation (workbook, sheet, vtype, vstyle, voperator, errmsg, errtitle, vprompt, allowblank, showinpmsg, showerrmsg, formula, formula1, formula2) ; VALUES (tnWB, tnSheet, lnValidType, lnValidStyle, lnOperator, lcErrMsg, lcErrTitle, lcPrompt, llAllowBlank, llShowInputMsg, llShowErrMsg, llFormula, lcFormula1, lcFormula2) lnIndex = xl_validation.validndx loCell = this.CellRefAsciiToIndex(lcValidSqRef) IF this.GetCellRecord(tnWB, tnSheet, loCell.Row, loCell.Column) REPLACE xl_cells.validndx WITH lnIndex IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, loCell.Row, loCell.Column, DATA_TYPE_NONE, 0, False, -1, lnIndex) this.SetRowMaxColumn(tnWB, tnSheet, loCell.Row, loCell.Column) ENDIF ENDFOR RETURN True ENDPROC PROTECTED PROCEDURE readstylesxml && Reads the styles.xml file for opening a workbook LPARAMETERS tcFilePath, tnWB LOCAL lcCellXfs, lnCnt, lcXf, lnIndent, lnWrapTx, lcAlign, lcStyleSheet, lnNode, lnNumFmtId, lnFontId, lnFillId, lnBorderId LOCAL lcHAlign, lcVAlign, lcNumFmts, lcFonts, lcNumFmt, lcFormatCode, lcFont, lnIndexed, lnFSize, lcFName, llFBold, llFItalic, llStrkthr LOCAL lcFVPos, lcULine, lnFColor, lnTheme, lnTint, lcColor, lcFills, lcFill, lcPatternFill, lcPatternType, lnFgColor, lnFgIndexed, lcBorder LOCAL lnBgColor, lnBgIndexed, lcBorders, lcBLeft, lcLStyle, lnLColor, lnLTheme, lnLTint, lnLIndex, lcBRight, lcRStyle, lnRColor, lnRTheme LOCAL lnRTint, lnRIndex, lcBTop, lcTStyle, lnTColor, lnTTheme, lnTTint, lnTIndex, lcBBottm, lcBStyle, lnBColor, lnBTheme, lnBTint, lnBIndex LOCAL lnDTint, lnDIndex, lcBDiag, lcDStyle, lnDColor, lnDTheme, lcIndexedColors, lcRgbColor, lcMruColors, lnIdCnt RAISEEVENT(this, "OnShowStatusMessage", 1, 2) *-* Open the styles sheet for processing lcStyleSheet = FILETOSTR(ADDBS(tcFilePath) + "xl\styles.xml") *-* Retreive the cell format mapping information lnIdCnt = -1 lcCellXfs = this.GetNodeElement(lcStyleSheet, 'cellXfs', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcCellXfs, "count") AS I) FOR lnNode=1 TO lnCnt lcXf = this.GetNodeElement(lcCellXfs, 'xf', lnNode) IF EMPTY(lcXf) SET STEP ON LOOP ENDIF lnIdCnt = lnIdCnt + 1 lcAlign = this.GetNodeElement(lcXf, 'alignment', 1) lcHAlign = this.GetNodeAttributeValue(lcAlign, "horizontal") lcVAlign = this.GetNodeAttributeValue(lcAlign, "vertical") lnNumFmtId = CAST(this.GetNodeAttributeValue(lcXf, "numFmtId") AS I) lnFontId = CAST(this.GetNodeAttributeValue(lcXf, "fontId") AS I) lnFillId = CAST(this.GetNodeAttributeValue(lcXf, "fillId") AS I) lnBorderId = CAST(this.GetNodeAttributeValue(lcXf, "borderId") AS I) lnIndent = CAST(this.GetNodeAttributeValue(lcAlign, "indent") AS I) lnWrapTx = CAST(this.GetNodeAttributeValue(lcAlign, "wrapText") AS I) lnRotation = CAST(this.GetNodeAttributeValue(lcAlign, "textRotation") AS I) INSERT INTO xl_cellxfs (workbook, id, numFmtId, fontId, fillId, borderId, halign, valign, indent, wraptext, rotation) ; VALUES (tnWB, lnIdCnt, lnNumFmtId, lnFontId, lnFillId, lnBorderId, lcHAlign, lcVAlign, lnIndent, lnWrapTx, lnRotation) ENDFOR this.SetLastId(tnWB, lnIdCnt, "xl_cellxfs") *-* Retreive the number format information lnIdCnt = -1 lcNumFmts = this.GetNodeElement(lcStyleSheet, 'numFmts', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcNumFmts, "count") AS I) FOR lnNode=1 TO lnCnt lcNumFmt = this.GetNodeElement(lcNumFmts, 'numFmt', lnNode) IF EMPTY(lcNumFmt) SET STEP ON LOOP ENDIF lnNumFmtId = CAST(this.GetNodeAttributeValue(lcNumFmt, "numFmtId") AS I) lcFormatCode = this.GetNodeAttributeValue(lcNumFmt, "formatCode") INSERT INTO xl_numFmts (workbook, id, formatxml, formatcode, applydec) ; VALUES (tnWB, lnNumFmtId, lcFormatCode, this.GetStringXML(lcFormatCode), False) ENDFOR *-* Retreive the font informaton lnIdCnt = -1 lcFonts = this.GetNodeElement(lcStyleSheet, 'fonts', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcFonts, "count") AS I) FOR lnNode=1 TO lnCnt lcFont = this.GetNodeElement(lcFonts, 'font', lnNode) IF EMPTY(lcFont) SET STEP ON LOOP ENDIF lnIdCnt = lnIdCnt + 1 lnFSize = CAST(this.GetNodeAttributeValue(this.GetNodeElement(lcFont, 'sz', 1), "val") AS I) lnFSize = IIF(lnFSize>0, lnFSize, 10) lcFName = this.GetNodeAttributeValue(this.GetNodeElement(lcFont, 'name', 1), "val") llFBold = IIF(ATC("", lcFont)>0, True, False) llFItalic = IIF(ATC("", lcFont)>0, True, False) llStrkthr = IIF(ATC("", lcFont)>0, True, False) lcFVPos = this.GetNodeAttributeValue(this.GetNodeElement(lcFont, 'vertAlign', 1), "val") IF ATC("", lcFont) > 0 lcULine = UNDERLINE_SINGLE ELSE lcULine = this.GetNodeAttributeValue(this.GetNodeElement(lcFont, 'u', 1), "val") lcULine = IIF(EMPTY(lcULine), UNDERLINE_NONE, lcULine) ENDIF lcColor = this.GetNodeElement(lcFont, 'color', 1) lnFColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnIndexed = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) INSERT INTO xl_fonts (workbook, id, fname, fsize, fcolor, fbold, fitalic, uline, strkthr, fvpos, theme, tint, indexed) ; VALUES (tnWB, lnIdCnt, lcFName, lnFSize, lnFColor, llFBold, llFItalic, lcULine, llStrkthr, lcFVPos, lnTheme, lnTint, lnIndexed) ENDFOR this.SetLastId(tnWB, lnIdCnt, "xl_fonts") *-* Retreive the cell fill information lnIdCnt = -1 lcFills = this.GetNodeElement(lcStyleSheet, 'fills', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcFills, "count") AS I) FOR lnNode=1 TO lnCnt lcFill = this.GetNodeElement(lcFills, 'fill', lnNode) IF EMPTY(lcFill) SET STEP ON LOOP ENDIF lnIdCnt = lnIdCnt + 1 lcPatternFill = this.GetNodeElement(lcFill, 'patternFill', 1) lcPatternType = this.GetNodeAttributeValue(lcPatternFill, "patternType") lcPatternType = IIF(EMPTY(lcPatternType), "none", lcPatternType) lnTheme = CAST(this.GetNodeAttributeValue(lcPatternFill, "theme") AS I) lcColor = this.GetNodeElement(lcPatternFill, 'fgColor', 1) IF EMPTY(lcColor) lnFgColor = 0 lnFgIndexed = 0 ELSE lnFgColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnFgIndexed = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF lcColor = this.GetNodeElement(lcPatternFill, 'bgColor', 1) IF EMPTY(lcColor) lnBgColor = 0 lnBgIndexed = 0 ELSE lnBgColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnBgIndexed = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF INSERT INTO xl_fills (workbook, id, patttype, theme, tint, fgcolor, bgcolor, fgindexed, bgindexed) ; VALUES (tnWB, lnIdCnt, lcPatternType, lnTheme, lnTint, lnFgColor, lnBgColor, lnFgIndexed, lnBgIndexed) ENDFOR this.SetLastId(tnWB, lnIdCnt, "xl_fills") *-* Retreive the cell border information lnIdCnt = -1 lcBorders = this.GetNodeElement(lcStyleSheet, 'borders', 1) lnCnt = CAST(this.GetNodeAttributeValue(lcBorders, "count") AS I) FOR lnNode=1 TO lnCnt lcBorder = this.GetNodeElement(lcBorders, 'border', lnNode) IF EMPTY(lcBorder) SET STEP ON LOOP ENDIF lnIdCnt = lnIdCnt + 1 lcBLeft = this.GetNodeElement(lcBorder, 'left', 1) lcLStyle = this.GetNodeAttributeValue(lcBLeft, "style") lcColor = this.GetNodeElement(lcBLeft, 'color', 1) IF EMPTY(lcColor) lnLColor = RGB(0, 0, 0) lnLTheme = 0 lnLTint = 0 lnLIndex = 0 ELSE lnLColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnLTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnLTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnLIndex = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF lcBRight = this.GetNodeElement(lcBorder, 'right', 1) lcRStyle = this.GetNodeAttributeValue(lcBRight, "style") lcColor = this.GetNodeElement(lcBRight, 'color', 1) IF EMPTY(lcColor) lnRColor = RGB(0, 0, 0) lnRTheme = 0 lnRTint = 0 lnRIndex = 0 ELSE lnRColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnRTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnRTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnRIndex = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF lcBTop = this.GetNodeElement(lcBorder, 'top', 1) lcTStyle = this.GetNodeAttributeValue(lcBTop, "style") lcColor = this.GetNodeElement(lcBTop, 'color', 1) IF EMPTY(lcColor) lnTColor = RGB(0, 0, 0) lnTTheme = 0 lnTTint = 0 lnTIndex = 0 ELSE lnTColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnTTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnTTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnTIndex = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF lcBBottm = this.GetNodeElement(lcBorder, 'bottom', 1) lcBStyle = this.GetNodeAttributeValue(lcBBottm, "style") lcColor = this.GetNodeElement(lcBBottm, 'color', 1) IF EMPTY(lcColor) lnBColor = RGB(0, 0, 0) lnBTheme = 0 lnBTint = 0 lnBIndex = 0 ELSE lnBColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnBTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnBTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnBIndex = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF lcBDiag = this.GetNodeElement(lcBorder, 'diagonal', 1) lcDStyle = this.GetNodeAttributeValue(lcBDiag, "style") lnDiagDn = CAST(this.GetNodeAttributeValue(lcBDiag, "diagonalDown") AS I) lnDiagUp = CAST(this.GetNodeAttributeValue(lcBDiag, "diagonalUp") AS I) lcColor = CAST(this.GetNodeElement(lcBDiag, 'color', 1) AS I) IF EMPTY(lcColor) lnDColor = RGB(0, 0, 0) lnDTheme = 0 lnDTint = 0 lnDIndex = 0 ELSE lnDColor = this.ConvertHexStringToNumeric(this.GetNodeAttributeValue(lcColor, "rgb")) lnDTheme = CAST(this.GetNodeAttributeValue(lcColor, "theme") AS I) lnDTint = CAST(this.GetNodeAttributeValue(lcColor, "tint") AS I) lnDIndex = CAST(this.GetNodeAttributeValue(lcColor, "indexed") AS I) ENDIF INSERT INTO xl_borders (workbook, id, lstyle, lcolor, ltheme, ltint, lindexed, rstyle, rcolor, rtheme, rtint, rindexed, tstyle, tcolor, ttheme, ttint, tindexed, ; bstyle, bcolor, btheme, btint, bindexed, dstyle, dcolor, dtheme, dtint, dindexed, diagdn, diagup) ; VALUES (tnWB, lnIdCnt, lcLStyle, lnLColor, lnLTheme, lnLTint, lnLIndex, lcRStyle, lnRColor, lnRTheme, lnRTint, lnRIndex, lcTStyle, lnTColor, lnTTheme, ; lnTTint, lnTIndex, lcBStyle, lnBColor, lnBTheme, lnBTint, lnBIndex, lcDStyle, lnDColor, lnDTheme, lnDTint, lnDIndex, lnDiagDn, lnDiagUp) ENDFOR this.SetLastId(tnWB, lnIdCnt, "xl_borders") *-* Retreive the indexed color information lcColors = this.GetNodeElement(lcStyleSheet, 'colors', 1) IF !EMPTY(lcColors) lcIndexedColors = this.GetNodeElement(lcColors, 'indexedColors', 1) IF !EMPTY(lcIndexedColors) lnNode = 1 lcRgbColor = this.GetNodeElement(lcIndexedColors, 'rgbColor', lnNode) DO WHILE !EMPTY(lcRgbColor) lcHexColor = this.GetNodeAttributeValue(lcRgbColor, "rgb") INSERT INTO xl_ndxcolors (workbook, indexid, rgbcolor) VALUES (tnWB, lnNode, lcHexColor) lnNode = lnNode + 1 lcRgbColor = this.GetNodeElement(lcIndexedColors, 'rgbColor', lnNode) ENDDO this.SetLastId(tnWB, lnNode-1, "xl_ndxcolors") ENDIF lcMruColors = this.GetNodeElement(lcColors, 'mruColors', 1) IF !EMPTY(lcMruColors) lnNode = 1 lcRgbColor = this.GetNodeElement(lcMruColors, 'color', lnNode) DO WHILE !EMPTY(lcRgbColor) lcHexColor = this.GetNodeAttributeValue(lcRgbColor, "rgb") INSERT INTO xl_mrucolors (workbook, indexid, rgbcolor) VALUES (tnWB, lnNode, lcHexColor) lnNode = lnNode + 1 lcRgbColor = this.GetNodeElement(lcMruColors, 'color', lnNode) ENDDO this.SetLastId(tnWB, lnNode-1, "xl_mrucolors") ENDIF ENDIF ENDPROC PROTECTED PROCEDURE removeworkingdirectories && Removes the working directories LPARAMETERS tcDir LOCAL llReturn, loException TRY llReturn = IIF(apiRemoveDirectory(tcDir) != 0, True, False) CATCH TO loException SET STEP ON llReturn = False ENDTRY RETURN llReturn ENDPROC PROCEDURE renamesheet && Renames the selected sheet LPARAMETERS tnWB, txSheet, tcSheetName LOCAL llReturn llReturn = False DO CASE CASE VARTYPE(txSheet) = "C" IF SEEK(BINTOC(tnWB)+UPPER(txSheet), "xl_sheets", "shname") REPLACE xl_sheets.shname WITH tcSheetName IN xl_sheets llReturn = True ENDIF CASE VARTYPE(txSheet) = "N" IF SEEK(BINTOC(tnWB)+BINTOC(txSheet), "xl_sheets", "sheetndx") REPLACE xl_sheets.shname WITH tcSheetName IN xl_sheets llReturn = True ENDIF ENDCASE RETURN llReturn ENDPROC PROCEDURE resetcolumnwidth && Resets the column width to default LPARAMETERS tnWB, tnSheet, tnColumn IF SEEK(this.GetColWidthKeyExpr(tnWB, tnSheet, tnColumn), "xl_colwidths", "shcolumn") DELETE IN xl_colwidths ENDIF ENDPROC PROTECTED PROCEDURE saveasutf8 && Saves the file as a UTF-8 LPARAMETERS tcFileName STRTOFILE(STRCONV(FILETOSTR(tcFileName), 9), tcFileName, 4) ENDPROC PROCEDURE savegridtoworkbook && Saves the selected grid to a workbook LPARAMETERS toGrid, txWB, tlFreeze, tlSaveWB, tcSheetName, tlInclHiddenCols LOCAL lcAlias, lnCol, lnWB, lnSh, lnRow, lcField, loReturn, loColumn, lnStyle, lnColCount, lnDefStyle LOCAL ARRAY laRowCount[1], laColOrder[1] loReturn = CREATEOBJECT("Empty") ADDPROPERTY(loReturn, "Workbook", 0) ADDPROPERTY(loReturn, "Sheet", 0) DO CASE CASE PCOUNT() = 0 RETURN loReturn CASE PCOUNT() = 1 RETURN loReturn CASE PCOUNT() = 2 tlFreeze = True tlSaveWB = True tcSheetName = this.DeriveSheetName(txWB) tlInclHiddenCols = True CASE PCOUNT() = 3 tlSaveWB = True tcSheetName = this.DeriveSheetName(txWB) tlInclHiddenCols = True CASE PCOUNT() = 4 tcSheetName = this.DeriveSheetName(txWB) tlInclHiddenCols = True CASE PCOUNT() = 5 tlInclHiddenCols = True ENDCASE IF VARTYPE(tcSheetName) != 'C' .OR. EMPTY(tcSheetName) tcSheetName = this.DeriveSheetName(txWB) ENDIF tcSheetName = CHRTRAN(tcSheetName, ":\/?*", "_____") IF LEN(tcSheetName) > LIMITS_MAX_SH_NAME IF this.AutoTrimSheetName tcSheetName = LEFT(ALLTRIM(tcSheetName), LIMITS_MAX_SH_NAME) ELSE RETURN loReturn ENDIF ENDIF IF VARTYPE(toGrid) != "O" .AND. PEMSTATUS(toGrid, "BaseClass", 5) .AND. LOWER(toGrid.BaseClass) != "grid" RETURN loReturn ENDIF DO CASE CASE VARTYPE(txWB) = "C" lnWB = this.CreateWorkbook(txWB) IF lnWB = 0 lnWB = this.GetWorkbook(txWB) ENDIF CASE VARTYPE(txWB) = "N" IF SEEK(BINTOC(txWB), "xl_workbooks", "workbook") lnWB = txWB ELSE RETURN loReturn ENDIF OTHERWISE RETURN loReturn ENDCASE IF lnWB > 0 lnSh = this.AddSheet(lnWB, tcSheetName) IF lnSh > 0 lcAlias = JUSTSTEM(toGrid.RecordSource) *-* Get the record count and display a status window SELECT COUNT(*) FROM &lcAlias INTO ARRAY laRowCount RAISEEVENT(this, "OnShowStatusMessage", 3, 0, laRowCount[1]) *-* Get the number of columns to process and *-* Get the column output order based on grid display order && Change requested by Matt Slay to output by grid display order and visible setting IF tlInclHiddenCols lnColCount = toGrid.ColumnCount DIMENSION laColOrder[lnColCount, 2] FOR lnCol=1 TO toGrid.ColumnCount laColOrder[lnCol, 1] = toGrid.Columns(lnCol).ColumnOrder && Grid display order laColOrder[lnCol, 2] = lnCol && Column property order ENDFOR ELSE lnColCount = 0 FOR lnCol=1 TO toGrid.ColumnCount IF toGrid.Columns(lnCol).Visible lnColCount = lnColCount + 1 DIMENSION laColOrder[lnColCount, 2] laColOrder[lnColCount, 1] = toGrid.Columns(lnCol).ColumnOrder && Grid display order laColOrder[lnColCount, 2] = lnCol && Column property order ENDIF ENDFOR ENDIF IF lnColCount = 0 RETURN False ENDIF ASORT(laColOrder) *-* Add the header row if defined and set the column widths; get the column font info IF toGrid.HeaderHeight > 0 && Change recommendation by Doug Hennig (if no headers, start in first row) lnRow = 1 FOR lnCol=1 TO lnColCount loColumn = toGrid.Columns(laColOrder[lnCol, 2]) this.SetCellValue(lnWB, lnSh, 1, lnCol, loColumn.Header1.Caption) this.SetColumnWidth(lnWB, lnSh, lnCol, this.ConvertPixelsToExcelUnits(loColumn.Width)) ENDFOR ELSE lnRow = 0 FOR lnCol=1 TO lnColCount loColumn = toGrid.Columns(laColOrder[lnCol, 2]) this.SetColumnWidth(lnWB, lnSh, lnCol, this.ConvertPixelsToExcelUnits(loColumn.Width)) ENDFOR ENDIF *-* Add the cell data values SELECT &lcAlias SCAN lnRow = lnRow + 1 RAISEEVENT(this, "OnShowStatusMessage", 3, lnRow) FOR lnCol=1 TO lnColCount loColumn = toGrid.Columns(laColOrder[lnCol, 2]) lcField = loColumn.ControlSource this.SetCellValue(lnWB, lnSh, lnRow, lnCol, &lcField) ENDFOR ENDSCAN *-* Set the cell style formatting lnDefStyle = this.IsFormatStyleDefined(lnWB, this.DefaultFont, this.DefaultFontSize) IF ISNULL(lnDefStyle) lnDefStyle = this.CreateFormatStyle(lnWB) this.AddStyleFont(lnWB, lnDefStyle, this.DefaultFont, this.DefaultFontSize) ENDIF FOR lnCol=1 TO lnColCount loColumn = toGrid.Columns(laColOrder[lnCol, 2]) lcField = loColumn.ControlSource IF VARTYPE(&lcField) != DATA_TYPE_DATE IF this.DefaultFont != loColumn.FontName .OR. this.DefaultFontSize != loColumn.FontSize && Change recommended by Doug Hennig; 2017-06-12 lnStyle = this.IsFormatStyleDefined(lnWB, loColumn.FontName, loColumn.FontSize) IF ISNULL(lnStyle) lnStyle = this.CreateFormatStyle(lnWB) this.AddStyleFont(lnWB, lnStyle, loColumn.FontName, loColumn.FontSize) ENDIF ELSE lnStyle = lnDefStyle ENDIF this.SetCellStyleRange(lnWB, lnSh, 1, lnCol, laRowCount[1]+1, lnCol, lnStyle) ENDIF ENDFOR *-* Freeze the first row if specified IF tlFreeze this.FreezePanes(lnWB, lnSh, 1, 0) ENDIF RAISEEVENT(this, "OnShowStatusMessage", 3, -1) IF tlSaveWB this.SaveWorkbook(lnWB) ENDIF loReturn.Sheet = lnSh loReturn.Workbook = lnWB ENDIF ENDIF RETURN loReturn ENDPROC PROCEDURE savegridtoworkbookex && Saves the passed grid to a workbook without adding the content to the internal cursors LPARAMETERS toGrid, tcFileName, tlFreeze, tcSheetName, tlInclHiddenCols LOCAL llError, lcTempPath, lcAlias, lcFileName, lhFile, lcRowDefHt, lnCol, lnRow, lcSETCentury, lxCellValue LOCAL lnColCount, lnColWidth, lcCurAlias LOCAL ARRAY laColOrder[1], laSheetNames[1] llError = False lcCurAlias = ALIAS() IF VARTYPE(toGrid) != "O" .AND. PEMSTATUS(toGrid, "BaseClass", 5) .AND. LOWER(toGrid.BaseClass) != "grid" RETURN False ENDIF DO CASE CASE PCOUNT() < 2 RETURN False CASE PCOUNT() = 2 tlFreeze = True tcSheetName = toGrid.Name tlInclHiddenCols = True CASE PCOUNT() = 3 tcSheetName = toGrid.Name tlInclHiddenCols = True CASE PCOUNT() = 4 tlInclHiddenCols = True ENDCASE IF VARTYPE(tcSheetName) != 'C' .OR. EMPTY(tcSheetName) tcSheetName = toGrid.Name ENDIF tcSheetName = CHRTRAN(tcSheetName, ":\/?*", "_____") IF LEN(tcSheetName) > LIMITS_MAX_SH_NAME IF this.AutoTrimSheetName tcSheetName = LEFT(ALLTRIM(tcSheetName), LIMITS_MAX_SH_NAME) ELSE RETURN False ENDIF ENDIF *-* Set temporary output path lcTempPath = this.CreateWorkingDirectories() IF ISNULL(lcTempPath) RETURN False ENDIF *-* Save current settings and then set to US formats lcSetPoint = SET("POINT") lcSeparator = SET("SEPARATOR") IF lcSetPoint != "." SET POINT TO "." SET SEPARATOR TO "," ENDIF *-* Output the workbook lcAlias = JUSTSTEM(toGrid.RecordSource) *-* Get the number of columns to process *-* Get the column output order based on grid display order && Change requested by Matt Slay to output by grid display order and visible setting IF tlInclHiddenCols lnColCount = toGrid.ColumnCount DIMENSION laColOrder[lnColCount, 2] FOR lnCol=1 TO toGrid.ColumnCount laColOrder[lnCol, 1] = toGrid.Columns(lnCol).ColumnOrder && Grid display order laColOrder[lnCol, 2] = lnCol && Column property order ENDFOR ELSE lnColCount = 0 FOR lnCol=1 TO toGrid.ColumnCount IF toGrid.Columns(lnCol).Visible lnColCount = lnColCount + 1 DIMENSION laColOrder[lnColCount, 2] laColOrder[lnColCount, 1] = toGrid.Columns(lnCol).ColumnOrder && Grid display order laColOrder[lnColCount, 2] = lnCol && Column property order ENDIF ENDFOR ENDIF IF lnColCount = 0 RETURN False ENDIF ASORT(laColOrder) DIMENSION laSheetNames[1] laSheetNames[1] = tcSheetName IF this.WriteDirectXMLs(lcTempPath, @laSheetNames) *-* Write the sheet XML TRY lcFileName = lcTempPath + "xl\worksheets\sheet1.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF *-* Write sheet XML header information FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Write the sheet view information which includes the freeze pane information FWRITE(lhFile, '') IF tlFreeze FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') ENDIF FWRITE(lhFile, '') *-* Write sheet Column widths FWRITE(lhFile, '') FOR lnCol=1 TO lnColCount lnColWidth = this.ConvertPixelsToExcelUnits(toGrid.Columns(laColOrder[lnCol, 2]).Width) FWRITE(lhFile, '') ENDFOR FWRITE(lhFile, '') *-* Write sheet cell data values lcRowDefHt = ' ht="30"' FWRITE(lhFile, '') *-* Place field names in the first row IF toGrid.HeaderHeight > 0 && Change recommendation by Doug Hennig (if no headers, then no output) FWRITE(lhFile, '') IF this.DefaultFont = "Calibri" .AND. this.DefaultFontSize = 11 FOR lnCol=1 TO lnColCount this.WriteAsInLineString(lhFile, 1, lnCol, toGrid.Columns(laColOrder[lnCol, 2]).Header1.Caption) ENDFOR ELSE FOR lnCol=1 TO lnColCount this.WriteAsInLineFormattedString(lhFile, 1, lnCol, toGrid.Columns(laColOrder[lnCol, 2]).Header1.Caption) ENDFOR ENDIF FWRITE(lhFile, '') lnRow = 1 ELSE lnRow = 0 ENDIF *-* Write the grid field values to cells lcSETCentury = SET("CENTURY") SET CENTURY ON SELECT &lcAlias IF this.DefaultFont = "Calibri" .AND. this.DefaultFontSize = 11 SCAN lnRow = lnRow + 1 FWRITE(lhFile, '') FOR lnCol=1 TO lnColCount lxCellValue = EVALUATE(toGrid.Columns(laColOrder[lnCol, 2]).ControlSource) this.WriteDirectCellValue(lhFile, lnRow, lnCol, lxCellValue) ENDFOR FWRITE(lhFile, '') ENDSCAN ELSE SCAN lnRow = lnRow + 1 FWRITE(lhFile, '') FOR lnCol=1 TO lnColCount lxCellValue = EVALUATE(toGrid.Columns(laColOrder[lnCol, 2]).ControlSource) this.WriteDirectCellFormattedValue(lhFile, lnRow, lnCol, lxCellValue) ENDFOR FWRITE(lhFile, '') ENDSCAN ENDIF SET CENTURY &lcSETCentury *-* End the sheet cell data values and worksheet FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CATCH TO loException SET STEP ON llError = True this.ErrorLevelId = 14 RAISEEVENT(this, "OnShowErrorMessage", 14, loException.message) FINALLY FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) ENDTRY IF llError llSuccess = False ELSE llSuccess = this.CreateExcelFile(lcTempPath, JUSTPATH(tcFileName), JUSTSTEM(tcFileName)) && Change recommendation by Doug Hennig [placement of code after ELSE] ENDIF this.RemoveWorkingDirectories(lcTempPath) ELSE llSuccess = False ENDIF IF !EMPTY(lcCurAlias) SELECT (lcCurAlias) ENDIF *-* Restore default settings IF lcSetPoint != "." SET POINT TO (lcSetPoint) SET SEPARATOR TO (lcSeparator) ENDIF RETURN llSuccess ENDPROC PROCEDURE savemultigridtoworkbookex && Same as SaveGridToWorkbookEx() method but handles multiple grids being passed LPARAMETERS toGrids, tcFileName LOCAL llError, lcTempPath, lcAlias, lcFileName, lhFile, lcRowDefHt, lnCol, lnRow, lcSETCentury, lxCellValue LOCAL lnColCount, lnColWidth, lcCurAlias, lnGrid, loGrid, loException, lcSheetName LOCAL ARRAY laColOrder[1], laSheetNames[1] llError = False lcCurAlias = ALIAS() IF PCOUNT() < 2 RETURN False ENDIF IF VARTYPE(toGrids) = "O" IF PEMSTATUS(toGrids, "Count", 5) .AND. VARTYPE(toGrids.Count) != "N" RETURN False ELSE IF toGrids.Count < 1 RETURN False ENDIF ENDIF IF PEMSTATUS(toGrids, "List", 5) llError = False TRY IF ALEN(toGrids.List, 2) != 4 && Column 1 Grid; Column 2 SheetName; Column 3 Freeze indicator, Column 4 HiddenCols indicator THROW ENDIF CATCH TO loException llError = True ENDTRY IF llError RETURN False ENDIF FOR lnGrid=1 TO toGrids.Count *-* Validate grid object loGrid = toGrids.List[lnGrid, 1] IF VARTYPE(loGrid) != "O" .AND. PEMSTATUS(loGrid, "BaseClass", 5) .AND. LOWER(loGrid.BaseClass) != "grid" RETURN False ENDIF *-* Validate sheet name lcSheetName = toGrids.List[lnGrid, 2] IF VARTYPE(lcSheetName) != 'C' .OR. EMPTY(lcSheetName) lcSheetName = loGrid.Name ENDIF lcSheetName = CHRTRAN(lcSheetName, ":\/?*", "_____") IF LEN(lcSheetName) > LIMITS_MAX_SH_NAME IF this.AutoTrimSheetName lcSheetName = LEFT(ALLTRIM(lcSheetName), LIMITS_MAX_SH_NAME) ELSE RETURN False ENDIF ENDIF toGrids.List[lnGrid, 2] = lcSheetName *-* Validate freeze indicator IF VARTYPE(toGrids.List[lnGrid, 3]) != 'L' toGrids.List[lnGrid, 3] = False ENDIF *-* Validate hidden column indicator IF VARTYPE(toGrids.List[lnGrid, 4]) != 'L' toGrids.List[lnGrid, 4] = False ENDIF ENDFOR ENDIF ELSE RETURN False ENDIF *-* Set temporary output path lcTempPath = this.CreateWorkingDirectories() IF ISNULL(lcTempPath) RETURN False ENDIF *-* Save current settings and then set to US formats lcSetPoint = SET("POINT") lcSeparator = SET("SEPARATOR") IF lcSetPoint != "." SET POINT TO "." SET SEPARATOR TO "," ENDIF *-* Output the workbook DIMENSION laSheetNames[toGrids.Count] FOR lnGrid=1 TO toGrids.Count laSheetNames[lnGrid] = toGrids.List[lnGrid, 2] ENDFOR IF !this.WriteDirectXMLs(lcTempPath, @laSheetNames) RETURN False ENDIF *-* Write the sheet xml for each grid FOR lnGrid=1 TO toGrids.Count loGrid = toGrids.List[lnGrid, 1] lcAlias = JUSTSTEM(loGrid.RecordSource) *-* Get the number of columns to process *-* Get the column output order based on grid display order && Change requested by Matt Slay to output by grid display order and visible setting IF toGrids.List[lnGrid, 4] lnColCount = loGrid.ColumnCount DIMENSION laColOrder[lnColCount, 2] FOR lnCol=1 TO loGrid.ColumnCount laColOrder[lnCol, 1] = loGrid.Columns(lnCol).ColumnOrder && Grid display order laColOrder[lnCol, 2] = lnCol && Column property order ENDFOR ELSE lnColCount = 0 FOR lnCol=1 TO loGrid.ColumnCount IF loGrid.Columns(lnCol).Visible lnColCount = lnColCount + 1 DIMENSION laColOrder[lnColCount, 2] laColOrder[lnColCount, 1] = loGrid.Columns(lnCol).ColumnOrder && Grid display order laColOrder[lnColCount, 2] = lnCol && Column property order ENDIF ENDFOR ENDIF IF lnColCount = 0 RETURN False ENDIF ASORT(laColOrder) TRY lcFileName = lcTempPath + "xl\worksheets\sheet" + TRANSFORM(lnGrid) + ".xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF *-* Write sheet XML header information FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Write the sheet view information which includes the freeze pane information FWRITE(lhFile, '') IF toGrids.List[lnGrid, 3] FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') ENDIF FWRITE(lhFile, '') *-* Write sheet Column widths FWRITE(lhFile, '') FOR lnCol=1 TO lnColCount lnColWidth = this.ConvertPixelsToExcelUnits(loGrid.Columns(laColOrder[lnCol, 2]).Width) FWRITE(lhFile, '') ENDFOR FWRITE(lhFile, '') *-* Write sheet cell data values lcRowDefHt = ' ht="30"' FWRITE(lhFile, '') *-* Place field names in the first row IF loGrid.HeaderHeight > 0 && Change recommendation by Doug Hennig (if no headers, then no output) FWRITE(lhFile, '') IF this.DefaultFont = "Calibri" .AND. this.DefaultFontSize = 11 FOR lnCol=1 TO lnColCount this.WriteAsInLineString(lhFile, 1, lnCol, loGrid.Columns(laColOrder[lnCol, 2]).Header1.Caption) ENDFOR ELSE FOR lnCol=1 TO lnColCount this.WriteAsInLineFormattedString(lhFile, 1, lnCol, loGrid.Columns(laColOrder[lnCol, 2]).Header1.Caption) ENDFOR ENDIF FWRITE(lhFile, '') lnRow = 1 ELSE lnRow = 0 ENDIF *-* Write the grid field values to cells lcSETCentury = SET("CENTURY") SET CENTURY ON SELECT &lcAlias IF this.DefaultFont = "Calibri" .AND. this.DefaultFontSize = 11 SCAN lnRow = lnRow + 1 FWRITE(lhFile, '') FOR lnCol=1 TO lnColCount lxCellValue = EVALUATE(loGrid.Columns(laColOrder[lnCol, 2]).ControlSource) this.WriteDirectCellValue(lhFile, lnRow, lnCol, lxCellValue) ENDFOR FWRITE(lhFile, '') ENDSCAN ELSE SCAN lnRow = lnRow + 1 FWRITE(lhFile, '') FOR lnCol=1 TO lnColCount lxCellValue = EVALUATE(loGrid.Columns(laColOrder[lnCol, 2]).ControlSource) this.WriteDirectCellFormattedValue(lhFile, lnRow, lnCol, lxCellValue) ENDFOR FWRITE(lhFile, '') ENDSCAN ENDIF SET CENTURY &lcSETCentury *-* End the sheet cell data values and worksheet FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CATCH TO loException SET STEP ON llError = True this.ErrorLevelId = 14 RAISEEVENT(this, "OnShowErrorMessage", 14, loException.message) FINALLY FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) ENDTRY ENDFOR IF llError llSuccess = False ELSE llSuccess = this.CreateExcelFile(lcTempPath, JUSTPATH(tcFileName), JUSTSTEM(tcFileName)) && Change recommendation by Doug Hennig [placement of code after ELSE] ENDIF *-* Cleanup this.RemoveWorkingDirectories(lcTempPath) IF !EMPTY(lcCurAlias) SELECT (lcCurAlias) ENDIF *-* Restore default settings IF lcSetPoint != "." SET POINT TO (lcSetPoint) SET SEPARATOR TO (lcSeparator) ENDIF RETURN llSuccess ENDPROC PROCEDURE savetabletoworkbook && Saves the table passed (alias) as a workbook sheet LPARAMETERS tcAlias, tnWB, tlFreeze, tlSaveWB, tcSheetName LOCAL lcAlias, lnCol, lnWB, lnSh, lnRow, lcField, lnFldCnt, llError, llOpenedTbl, loException, lcCurAlias, loReturn LOCAL lnNdx, lcCaption LOCAL ARRAY laFields[1], laRowCount[1] loReturn = CREATEOBJECT("Empty") ADDPROPERTY(loReturn, "Workbook", 0) ADDPROPERTY(loReturn, "Sheet", 0) DO CASE CASE PCOUNT() < 2 RETURN loReturn CASE PCOUNT() = 2 tlFreeze = True tlSaveWB = False tcSheetName = JUSTSTEM(tcAlias) CASE PCOUNT() = 3 tlSaveWB = False tcSheetName = JUSTSTEM(tcAlias) CASE PCOUNT() = 4 tcSheetName = JUSTSTEM(tcAlias) ENDCASE IF VARTYPE(tcSheetName) != 'C' .OR. EMPTY(tcSheetName) tcSheetName = this.DeriveSheetName(tnWB) ENDIF tcSheetName = CHRTRAN(tcSheetName, ":\/?*", "_____") IF LEN(tcSheetName) > LIMITS_MAX_SH_NAME IF this.AutoTrimSheetName tcSheetName = LEFT(ALLTRIM(tcSheetName), LIMITS_MAX_SH_NAME) ELSE RETURN loReturn ENDIF ENDIF DO CASE CASE USED(tcAlias) lcCurAlias = ALIAS() llOpenedTbl = False lcAlias = tcAlias CASE OCCURS("\", tcAlias) > 0 TRY lcAlias = JUSTSTEM(tcAlias) USE (tcAlias) IN 0 ALIAS (lcAlias) SHARED llOpenedTbl = True CATCH TO loException llError = True ENDTRY IF llError RETURN loReturn ENDIF OTHERWISE RETURN loReturn ENDCASE DO CASE CASE VARTYPE(tnWB) = "C" lnWB = this.CreateWorkbook(tnWB) IF lnWB = 0 lnWB = this.GetWorkbook(tnWB) ENDIF CASE VARTYPE(tnWB) = "N" IF SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") lnWB = tnWB ELSE RETURN loReturn ENDIF OTHERWISE RETURN loReturn ENDCASE IF lnWB > 0 lnSh = this.AddSheet(lnWB, tcSheetName) IF lnSh > 0 *-* Get the record count and display a status window SELECT COUNT(*) FROM &lcAlias INTO ARRAY laRowCount RAISEEVENT(this, "OnShowStatusMessage", 3, 0, laRowCount[1]) SELECT &lcAlias lnFldCnt = AFIELDS(laFields, lcAlias) FOR lnNdx=1 TO lnFldCnt TRY lcCaption = DBGETPROP(lcAlias + "." + laFields[lnNdx, 1], "FIELD", "CAPTION") laFields[lnNdx, 3] = IIF(EMPTY(lcCaption), laFields[lnNdx, 1], lcCaption) CATCH TO loException laFields[lnNdx, 3] = laFields[lnNdx, 1] ENDTRY ENDFOR *-* Place field names in the first row FOR lnCol=1 TO lnFldCnt this.SetCellValue(lnWb, lnSh, 1, lnCol, laFields[lnCol, 3]) ENDFOR *-* Populate next rows with data lnRow = 0 SCAN lnRow = lnRow + 1 RAISEEVENT(this, "OnShowStatusMessage", 3, lnRow) FOR lnCol=1 TO lnFldCnt IF laFields[lnCol, 2] = "G" this.SetCellValue(lnWb, lnSh, 1 + lnRow, lnCol, "General") ELSE this.SetCellValue(lnWb, lnSh, 1 + lnRow, lnCol, EVALUATE(lcAlias + '.' + laFields[lnCol, 1])) ENDIF ENDFOR ENDSCAN IF tlFreeze this.FreezePanes(lnWB, lnSh, 1, 0) ENDIF RAISEEVENT(this, "OnShowStatusMessage", 3, -1) IF tlSaveWB this.SaveWorkbook(lnWB) ENDIF ELSE lnWB = 0 lnSh = 0 ENDIF ELSE lnSh = 0 lnWB = 0 ENDIF IF llOpenedTbl USE IN &lcAlias ELSE lnSh = 0 lnWB = 0 IF !EMPTY(lcCurAlias) SELECT &lcCurAlias ENDIF ENDIF loReturn.Sheet = lnSh loReturn.Workbook = lnWB RETURN loReturn ENDPROC PROCEDURE savetabletoworkbookex && Creates a new workbook from a table; direct write to XLSX file without loading internal cursors LPARAMETERS tcAlias, tcXlsxName, taFields, tlFreeze, tcSheetName LOCAL lcCurAlias, llOpenedTbl, lcAlias, llError, loException, lhFile, lnCol, lcRowDefHt LOCAL lnFldCnt, lnRow, lxCellValue, lcTempPath, lcFileName, lcSETCentry, lcCaption, llSuccess, lcSetPoint LOCAL lcSeparator LOCAL ARRAY laSheetNames[1] EXTERNAL ARRAY taFields llError = False DO CASE CASE PCOUNT() < 2 RETURN False CASE PCOUNT() = 2 DIMENSION taFields[1, 2] taFields[1, 1] = .NULL. tlFreeze = True tcSheetName = JUSTSTEM(tcAlias) CASE PCOUNT() = 3 tlFreeze = True tcSheetName = JUSTSTEM(tcAlias) CASE PCOUNT() = 4 tcSheetName = JUSTSTEM(tcAlias) ENDCASE IF VARTYPE(tcSheetName) != 'C' .OR. EMPTY(tcSheetName) tcSheetName = JUSTSTEM(tcAlias) ENDIF tcSheetName = CHRTRAN(tcSheetName, ":\/?*", "_____") IF LEN(tcSheetName) > LIMITS_MAX_SH_NAME IF this.AutoTrimSheetName tcSheetName = LEFT(ALLTRIM(tcSheetName), LIMITS_MAX_SH_NAME) ELSE RETURN False ENDIF ENDIF lcCurAlias = ALIAS() lcAlias = JUSTSTEM(tcAlias) DO CASE CASE USED(lcAlias) llOpenedTbl = False CASE OCCURS("\", tcAlias) > 0 TRY USE (tcAlias) IN 0 ALIAS (lcAlias) SHARED llOpenedTbl = True CATCH TO loException llError = True ENDTRY IF llError RETURN False ENDIF OTHERWISE RETURN False ENDCASE *-* Get the table fields to export if not passed as a parameter SELECT &lcAlias IF ISNULL(taFields) .OR. EMPTY(taFields[1]) DIMENSION taFields[1, 5] taFields = "" lnFldCnt = AFIELDS(taFields, lcAlias) FOR lnCol=1 TO lnFldCnt TRY lcCaption = DBGETPROP(lcAlias + "." + taFields[lnCol, 1], "FIELD", "CAPTION") taFields[lnCol, 2] = IIF(EMPTY(lcCaption), taFields[lnCol, 1], lcCaption) CATCH TO loException taFields[lnCol, 2] = taFields[lnCol, 1] ENDTRY ENDFOR ELSE lnFldCnt = ALEN(taFields, 1) IF ALEN(taFields, 2) < 2 .OR. VARTYPE(taFields[1, 2]) != "C" RETURN False ENDIF ENDIF *-* Set temporary output path lcTempPath = this.CreateWorkingDirectories() IF ISNULL(lcTempPath) RETURN False ENDIF *-* Save current settings and then set to US formats lcSetPoint = SET("POINT") lcSeparator = SET("SEPARATOR") IF lcSetPoint != "." SET POINT TO "." SET SEPARATOR TO "," ENDIF DIMENSION laSheetNames[1] laSheetNames[1] = tcSheetName IF this.WriteDirectXMLs(lcTempPath, @laSheetNames) *-* Write the sheet XML TRY lcFileName = lcTempPath + "xl\worksheets\sheet1.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF *-* Write sheet XML header information FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Write the sheet view information which includes the freeze pane information FWRITE(lhFile, '') IF tlFreeze FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Write sheet cell data values FWRITE(lhFile, '') *-* Place field names in the first row lcRowDefHt = ' ht="30"' FWRITE(lhFile, '') IF this.DefaultFont = "Calibri" .AND. this.DefaultFontSize = 11 FOR lnCol=1 TO lnFldCnt this.WriteAsInLineString(lhFile, 1, lnCol, taFields[lnCol, 2]) ENDFOR ELSE FOR lnCol=1 TO lnFldCnt this.WriteAsInLineFormattedString(lhFile, 1, lnCol, taFields[lnCol, 2]) ENDFOR ENDIF FWRITE(lhFile, '') *-* Write the table field values to cells lcSETCentry = SET("CENTURY") SET CENTURY ON lnRow = 1 IF this.DefaultFont = "Calibri" .AND. this.DefaultFontSize = 11 SCAN lnRow = lnRow + 1 FWRITE(lhFile, '') FOR lnCol=1 TO lnFldCnt lxCellValue = EVALUATE(lcAlias + '.' + taFields[lnCol, 1]) this.WriteDirectCellValue(lhFile, lnRow, lnCol, lxCellValue) ENDFOR FWRITE(lhFile, '') ENDSCAN ELSE SCAN lnRow = lnRow + 1 FWRITE(lhFile, '') FOR lnCol=1 TO lnFldCnt lxCellValue = EVALUATE(lcAlias + '.' + taFields[lnCol, 1]) this.WriteDirectCellFormattedValue(lhFile, lnRow, lnCol, lxCellValue) ENDFOR FWRITE(lhFile, '') ENDSCAN ENDIF SET CENTURY &lcSETCentry *-* End the sheet cell data values and worksheet FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CATCH TO loException SET STEP ON llError = True this.ErrorLevelId = 14 RAISEEVENT(this, "OnShowErrorMessage", 14, loException.message) FINALLY FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) ENDTRY IF llError llSuccess = False ELSE *-* Create the XLSX file llSuccess = this.CreateExcelFile(lcTempPath, JUSTPATH(tcXlsxName), JUSTSTEM(tcXlsxName)) && Change recommendation by Doug Hennig [placement of code after ELSE] ENDIF this.RemoveWorkingDirectories(lcTempPath) ELSE llSuccess = False ENDIF IF !EMPTY(lcCurAlias) SELECT (lcCurAlias) ENDIF *-* Restore default settings IF lcSetPoint != "." SET POINT TO (lcSetPoint) SET SEPARATOR TO (lcSeparator) ENDIF RETURN llSuccess ENDPROC PROCEDURE saveworkbook && Saves the selected workbook as an XLSX file LPARAMETERS tnWB LOCAL lcTempPath, lnSheet, lcDeleted, lcSetPoint, lcSeparator, lcSetDeleted, llReturn, lcAlias LOCAL lcSafety, lnTotStages IF SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") llReturn = True lcAlias = ALIAS() lcSafety = SET("SAFETY") lcSetDeleted = SET("DELETED") lcSetPoint = SET("POINT") lcSeparator = SET("SEPARATOR") SET SAFETY OFF SET POINT TO "." SET SEPARATOR TO "," SET DELETED ON *-* Write the XLSX Workbook to XML structures lcTempPath = this.CreateWorkingDirectories() IF ISNULL(lcTempPath) llReturn = False ELSE SELECT xl_sheets COUNT FOR workbook = tnWB .AND. !shdeleted TO lnTotStages lnTotStages = lnTotStages + 5 RAISEEVENT(this, "OnShowStatusMessage", 2, 0, lnTotStages) IF this.WriteStringsXML(tnWB, lcTempPath) ; .AND. this.WriteSupportXMLs(tnWB, lcTempPath) ; .AND. this.WriteStylesXML(tnWB, lcTempPath) ; .AND. this.WriteWorkbookXML(tnWB, lcTempPath) ; .AND. this.WriteRelationshipsXML(tnWB, lcTempPath) lnSheet = 0 SELECT xl_sheets SET ORDER TO TAG sheet SCAN FOR workbook = tnWB .AND. !shdeleted lnSheet = lnSheet + 1 RAISEEVENT(this, "OnShowStatusMessage", 2, lnSheet+5) IF !this.WriteSheetXMLs(tnWB, xl_sheets.sheet, lcTempPath) llReturn = False EXIT ENDIF ENDSCAN SELECT xl_sheets SET ORDER TO IF llReturn .AND. SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") llReturn = this.CreateExcelFile(lcTempPath, xl_workbooks.filepath, xl_workbooks.wbname) ENDIF ELSE llReturn = False ENDIF this.RemoveWorkingDirectories(lcTempPath) RAISEEVENT(this, "OnShowStatusMessage", 2, -1) ENDIF SET SAFETY &lcSafety SET DELETED &lcSetDeleted SET POINT TO (lcSetPoint) SET SEPARATOR TO (lcSeparator) IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE saveworkbookas && Saves the selected workbook with the new name LPARAMETERS tnWB, tcWBName LOCAL lcName, lcPath IF SEEK(BINTOC(tnWB), "xl_workbooks", "workbook") .AND. !EMPTY(tcWBName) lcName = JUSTSTEM(tcWBName) lcPath = JUSTPATH(tcWBName) IF EMPTY(lcPath) lcPath = SYS(5) + SYS(2003) ENDIF REPLACE xl_workbooks.wbname WITH lcName, ; xl_workbooks.filepath WITH lcPath IN xl_workbooks this.SaveWorkbook(tnWB) ENDIF ENDPROC PROCEDURE setcellalignment && Sets the cell horizontal and vertical alignments LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tcHorizAlign, tcVertAlign LOCAL llReturn, lnCellXfsId, lcAlias IF PCOUNT() < 4 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) DO CASE CASE VARTYPE(tcHorizAlign) = 'C' .AND. VARTYPE(tcVertAlign) = 'C' IF INLIST(tcHorizAlign, CELL_HORIZ_ALIGN_LEFT, CELL_HORIZ_ALIGN_RIGHT, CELL_HORIZ_ALIGN_CENTER) .AND. ; INLIST(tcVertAlign, CELL_VERT_ALIGN_TOP, CELL_VERT_ALIGN_BOTTOM, CELL_VERT_ALIGN_CENTER) IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontId, xl_cellxfs.fillId, xl_cellxfs.borderId, tcHorizAlign, tcVertAlign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.halign WITH tcHorizAlign, ; xl_cellxfs.valign WITH tcVertAlign IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, tcHorizAlign, tcVertAlign, 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, tcHorizAlign, tcVertAlign, 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF CASE VARTYPE(tcHorizAlign) = 'C' .AND. VARTYPE(tcVertAlign) != 'C' IF INLIST(tcHorizAlign, CELL_HORIZ_ALIGN_LEFT, CELL_HORIZ_ALIGN_RIGHT, CELL_HORIZ_ALIGN_CENTER) IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontId, xl_cellxfs.fillId, xl_cellxfs.borderId, tcHorizAlign, "", xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.halign WITH tcHorizAlign, ; xl_cellxfs.valign WITH "" IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, tcHorizAlign, "", 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, tcHorizAlign, "", 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF CASE VARTYPE(tcHorizAlign) != 'C' .AND. VARTYPE(tcVertAlign) = 'C' IF INLIST(tcVertAlign, CELL_VERT_ALIGN_TOP, CELL_VERT_ALIGN_BOTTOM, CELL_VERT_ALIGN_CENTER) IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontId, xl_cellxfs.fillId, xl_cellxfs.borderId, "", tcVertAlign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.halign WITH "", ; xl_cellxfs.valign WITH tcVertAlign IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", tcVertAlign, 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", tcVertAlign, 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF OTHERWISE IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.halign WITH "", ; xl_cells.valign WITH "" IN xl_cells ENDIF llReturn = True ENDCASE ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellalignmentrange && Sets the cell alignment for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tcHorizAlign, tcVertAlign LOCAL lnRow, lnCol, llReturn IF PCOUNT() < 7 .OR. this.IsCellReferenceInvalid(tnBegRow, tnBegCol) .OR. this.IsCellReferenceInvalid(tnEndRow, tnEndCol) RETURN False ENDIF IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN False ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF !this.SetCellAlignment(tnWB, tnSheet, lnRow, lnCol, tcHorizAlign, tcVertAlign) llReturn = False EXIT ENDIF ENDFOR ENDFOR RETURN llReturn ENDPROC PROCEDURE setcellborder LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnBorders, tcStyle, tnColor LOCAL lcLStyle, lnLColor, lcRStyle, lcTStyle, lnTColor, lcBStyle, lnBColor, lcDStyle, lnDColor, lnDiagDn, lnDiagUp LOCAL lnRColor, llReturn, lcAlias IF PCOUNT() < 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF VARTYPE(tnBorders) != 'N' .OR. EMPTY(tnBorders) .OR. !BETWEEN(tnBorders, 0, 63) tnBorders = 0 ENDIF IF !this.IsValidBorderStyle(tcStyle) tcStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnColor) != 'N' .OR. !BETWEEN(tnColor, 0, RGB(255,255,255)) .OR. EMPTY(tnColor) tnColor = RGB(0, 0, 0) ENDIF STORE 0 TO lnDiagDn, lnDiagUp STORE RGB(0,0,0) TO lnLColor, lnRColor, lnTColor, lnBColor, lnDColor STORE BORDER_STYLE_NONE TO lcLStyle, lcRStyle, lcTStyle, lcBStyle, lcDStyle IF BITTEST(tnBorders, 0) lcLStyle = tcStyle lnLColor = tnColor ENDIF IF BITTEST(tnBorders, 1) lcRStyle = tcStyle lnRColor = tnColor ENDIF IF BITTEST(tnBorders, 2) lcTStyle = tcStyle lnTColor = tnColor ENDIF IF BITTEST(tnBorders, 3) lcBStyle = tcStyle lnBColor = tnColor ENDIF IF BITTEST(tnBorders, 4) lcDStyle = tcStyle lnDColor = tnColor lnDiagDn = 1 ENDIF IF BITTEST(tnBorders, 5) lcDStyle = tcStyle lnDColor = tnColor lnDiagUp = 1 ENDIF this.SetCellBorderEx(tnWB, tnSheet, tnCellRow, tnCellCol, lcLStyle, lnLColor, lcRStyle, lnRColor, ; lcTStyle, lnTColor, lcBStyle, lnBColor, lcDStyle, lnDColor, lnDiagDn, lnDiagUp) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellborderex LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tcLStyle, tnLColor, tcRStyle, tnRColor, tcTStyle, tnTColor, tcBStyle, tnBColor, tcDStyle, tnDColor, tnDiagDn, tnDiagUp LOCAL lnCellXfsId, lnBorderId IF PCOUNT() < 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF this.GetSheetRecord(tnWB, tnSheet) IF !this.IsValidBorderStyle(tcLStyle) tcLStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnLColor) != 'N' .OR. EMPTY(tnLColor) .OR. !BETWEEN(tnLColor, 0, RGB(255,255,255)) tnLColor = RGB(0, 0, 0) ENDIF IF !this.IsValidBorderStyle(tcRStyle) tcRStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnRColor) != 'N' .OR. EMPTY(tnRColor) .OR. !BETWEEN(tnRColor, 0, RGB(255,255,255)) tnRColor = RGB(0, 0, 0) ENDIF IF !this.IsValidBorderStyle(tcTStyle) tcTStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnTColor) != 'N' .OR. EMPTY(tnTColor) .OR. !BETWEEN(tnTColor, 0, RGB(255,255,255)) tnTColor = RGB(0, 0, 0) ENDIF IF !this.IsValidBorderStyle(tcBStyle) tcBStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnBColor) != 'N' .OR. EMPTY(tnBColor) .OR. !BETWEEN(tnBColor, 0, RGB(255,255,255)) tnBColor = RGB(0, 0, 0) ENDIF IF !this.IsValidBorderStyle(tcDStyle) tcDStyle = BORDER_STYLE_NONE ENDIF IF VARTYPE(tnDColor) != 'N' .OR. EMPTY(tnDColor) .OR. !BETWEEN(tnDColor, 0, RGB(255,255,255)) tnDColor = RGB(0, 0, 0) ENDIF IF VARTYPE(tnDiagDn) != 'N' .OR. !BETWEEN(tnDiagDn, 0, 3) tnDiagDn = 0 ENDIF IF VARTYPE(tnDiagUp) != 'N' .OR. !BETWEEN(tnDiagUp, 0, 3) tnDiagUp = 0 ENDIF *-* Get the border record Id IF this.GetBordersRecord(tnWB, tcLStyle, tnLColor, tcRStyle, tnRColor, tcTStyle, tnTColor, tcBStyle, tnBColor, tcDStyle, tnDColor, tnDiagDn, tnDiagUp) lnBorderId = xl_borders.id ELSE lnBorderId = this.GetNextId(tnWB, 'xl_borders') INSERT INTO xl_borders (workbook, id, lstyle, lcolor, rstyle, rcolor, tstyle, tcolor, bstyle, bcolor, dstyle, dcolor, diagdn, diagup) ; VALUES (tnWB, lnBorderId, tcLStyle, tnLColor, tcRStyle, tnRColor, tcTStyle, tnTColor, tcBStyle, tnBColor, tcDStyle, tnDColor, tnDiagDn, tnDiagUp) ENDIF *-* Set the XfsId to the cell record IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontId, xl_cellxfs.fillId, lnBorderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.borderId WITH lnBorderId IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, lnBorderId, "", "", 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, lnBorderId, "", "", 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF RETURN llReturn ENDPROC PROCEDURE setcellborderrange && Sets the cell border for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tnBorder, tcStyle, tnColor LOCAL llReturn, lnRow, lnCol IF PCOUNT() < 7 .OR. this.IsCellReferenceInvalid(tnBegRow, tnBegCol) .OR. this.IsCellReferenceInvalid(tnEndRow, tnEndCol) RETURN False ENDIF IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN False ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF !this.SetCellBorder(tnWB, tnSheet, lnRow, lnCol, tnBorder, tcStyle, tnColor) llReturn = False EXIT ENDIF ENDFOR ENDFOR RETURN llReturn ENDPROC PROCEDURE setcellfill && Sets the fill color for the cell LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnFColor, tnBColor, tcPatternType LOCAL llReturn, lnFillId, lnCellXfsId, lnFIndex, lnBIndex, lcAlias DO CASE CASE PCOUNT() < 5 RETURN False CASE PCOUNT() = 5 tnBColor = RGB(255,255,255) tcPatternType = FILL_STYLE_SOLID CASE PCOUNT() = 6 tcPatternType = FILL_STYLE_SOLID ENDCASE IF this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() IF PCOUNT() = 5 .OR. PCOUNT() = 6 .OR. VARTYPE(tcPatternType) != "C" .OR. EMPTY(tcPatternType) tcPatternType = FILL_STYLE_SOLID ENDIF IF this.GetSheetRecord(tnWB, tnSheet) IF VARTYPE(tnBColor) != 'N' tnBColor = RGB(255,255,255) ENDIF IF VARTYPE(tnFColor) = 'N' .AND. BETWEEN(tnFColor, 0, RGB(255, 255, 255)) tnFColor = FLOOR(tnFColor) lnFIndex = 0 ELSE tnFColor = 0 lnFIndex = 64 ENDIF IF VARTYPE(tnBColor) = 'N' .AND. BETWEEN(tnBColor, 0, RGB(255, 255, 255)) tnBColor = FLOOR(tnBColor) lnBIndex = 0 ELSE tnBColor = RGB(0, 0, 0) lnBIndex = 64 ENDIF *-* Get the fill record id IF SEEK(BINTOC(tnWB)+BINTOC(tnFColor)+BINTOC(tnBColor)+tcPatternType, "xl_fills", "fillcolor") lnFillId = xl_fills.id REPLACE xl_fills.theme WITH 0, ; xl_fills.tint WITH 0, ; xl_fills.fgindexed WITH lnFIndex, ; xl_fills.bgindexed WITH lnBIndex IN xl_fills ELSE lnFillId = this.GetNextId(tnWB, 'xl_fills') INSERT INTO xl_fills (workbook, id, fgcolor, bgcolor, patttype, theme, tint, fgindexed, bgindexed) ; VALUES (tnWB, lnFillId, tnFColor, tnBColor, tcPatternType, 0, 0, lnFIndex, lnBIndex) ENDIF *-* Set the XfsId to the cell record IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontId, lnFillId, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.fillId WITH lnFillId IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, lnFillId, 0, "", "", 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, lnFillId, 0, "", "", 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellfillrange && Sets the fill for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tnFColor, tnBColor, tcPatternType LOCAL lnRow, lnCol, llReturn DO CASE CASE PCOUNT() < 7 RETURN False CASE PCOUNT() = 7 tnBColor = RGB(255,255,255) tcPatternType = FILL_STYLE_SOLID CASE PCOUNT() = 8 tcPatternType = FILL_STYLE_SOLID ENDCASE IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol .OR. this.IsCellReferenceInvalid(tnBegRow, tnBegCol) .OR. this.IsCellReferenceInvalid(tnEndRow, tnEndCol) RETURN False ENDIF IF VARTYPE(tnBColor) != 'N' tnBColor = RGB(255,255,255) ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF !this.SetCellFill(tnWB, tnSheet, lnRow, lnCol, tnFColor, tnBColor, tcPatternType) llReturn = False EXIT ENDIF ENDFOR ENDFOR RETURN llReturn ENDPROC PROCEDURE setcellfont && Sets the selected cell font format LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos LOCAL llReturn, lcAlias IF PCOUNT() < 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF VARTYPE(tcFName) != 'C' .OR. EMPTY(tcFName) tcFName = 'Calibri' ENDIF tcFName = PROPER(ALLTRIM(tcFName)) IF VARTYPE(tnFSize) != 'N' .OR. EMPTY(tnFSize) .OR. tnFSize < 0.5 tnFSize = 11 ELSE tnFSize = INT(tnFSize) ENDIF IF VARTYPE(tlBold) != 'L' tlBold = False ENDIF IF VARTYPE(tlItalic) != 'L' tlItalic = False ENDIF IF VARTYPE(tnFColor) = 'N' .AND. BETWEEN(tnFColor, 0, RGB(255, 255, 255)) tnFColor = FLOOR(tnFColor) ELSE tnFColor = RGB(0, 0, 0) ENDIF IF VARTYPE(tlStrikThr) != 'L' tlStrikThr = False ENDIF IF VARTYPE(tcULine) != 'C' .OR. !INLIST(tcULine, UNDERLINE_SINGLE, UNDERLINE_DOUBLE, UNDERLINE_SINGLEACCOUNTING, UNDERLINE_DOUBLEACCOUNTING, UNDERLINE_NONE) tcULine = UNDERLINE_NONE ENDIF IF VARTYPE(tcVPos) != 'C' .OR. !INLIST(tcVPos, FONT_VERTICAL_BASELINE, FONT_VERTICAL_SUBSCRIPT, FONT_VERTICAL_SUPERSCRIPT) tcVPos = FONT_VERTICAL_BASELINE ENDIF *-* Get the font record id IF SEEK(BINTOC(tnWB)+PADR(tcFName, 100) + STR(tnFSize, 5, 1) + TRANSFORM(tlBold) + TRANSFORM(tlItalic) + PADL(tnFColor, 15) + PADR(tcULine, 16) + ; TRANSFORM(tlStrikThr) + PADR(tcVPos, 11), "xl_fonts", "cellformat") lnFontId = xl_fonts.id REPLACE xl_fonts.theme WITH 0, ; xl_fonts.tint WITH 0, ; xl_fonts.indexed WITH 0 IN xl_fonts ELSE lnFontId = this.GetNextId(tnWB, 'xl_fonts') INSERT INTO xl_fonts (workbook, id, fname, fsize, fbold, fitalic, fcolor, uline, strkthr, fvpos) ; VALUES (tnWB, lnFontId, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos) ENDIF *-* Set the XfsId to the cell record IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, lnFontId, xl_cellxfs.fillid, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.fontid WITH lnFontId IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, lnFontId, 0, 0, "", "", 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, lnFontId, 0, 0, "", "", 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellfontrange && Sets the cell font format for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos LOCAL lnRow, lnCol, llReturn IF PCOUNT() < 7 .OR. this.IsCellReferenceInvalid(tnBegRow, tnBegCol) .OR. this.IsCellReferenceInvalid(tnEndRow, tnEndCol) RETURN False ENDIF IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN False ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF !this.SetCellFont(tnWB, tnSheet, lnRow, lnCol, tcFName, tnFSize, tlBold, tlItalic, tnFColor, tcULine, tlStrikThr, tcVPos) llReturn = False EXIT ENDIF ENDFOR ENDFOR RETURN llReturn ENDPROC PROCEDURE setcellformula && Sets the cell formula expression LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tcCellFormula LOCAL llReturn, lcAlias IF PCOUNT() < 5 .OR. VARTYPE(tcCellFormula) != "C" .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.cellvalue WITH "", ; xl_cells.cellformula WITH tcCellFormula, ; xl_cells.stringid WITH 0, ; xl_cells.datatype WITH DATA_TYPE_FORMULA, ; xl_cells.celldeleted WITH False IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, cellformula, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, tcCellFormula, DATA_TYPE_FORMULA, 0, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellindent && Sets the cell indentation value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnIndent LOCAL lnCellXfsId, lcAlias IF PCOUNT() != 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF VARTYPE(tnIndent) != 'N' RETURN False ENDIF lcAlias = ALIAS() tnIndent = FLOOR(tnIndent) IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontid, xl_cellxfs.fillid, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, tnIndent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.indent WITH tnIndent IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", "", tnIndent, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", "", tnIndent, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ENDPROC PROCEDURE setcellinlineformattext && Saves the in-line format definition to a cell value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, toInLine LOCAL lnNdx, lcRText, llFBold, llFItalic, lnFColor, lcFName, lnFSize, lcULine, llStrkThr, lcFVPos, lcAlias IF this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF tnWB = toInLine.Workbook lcAlias = ALIAS() IF ISNULL(toInLine.StringId) toInLine.StringId = this.AddStringValue(toInLine.Workbook, toInLine.StringValue, True) ENDIF IF this.GetCellRecord(toInLine.Workbook, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.cellvalue WITH "StringValue", ; xl_cells.cellxfs WITH 0, ; xl_cells.cellformula WITH "", ; xl_cells.stringid WITH toInLine.StringId, ; xl_cells.datatype WITH DATA_TYPE_CHAR, ; xl_cells.celldeleted WITH False IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, cellvalue, stringid, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (toInLine.Workbook, tnSheet, tnCellRow, tnCellCol, "StringValue", toInLine.StringId, DATA_TYPE_CHAR, 0, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF FOR lnNdx=1 TO toInLine.Count lcRText = SUBSTR(toInLine.StringValue, toInLine.Characters[lnNdx].BegPos, toInLine.Characters[lnNdx].Length) llFBold = toInLine.Characters[lnNdx].FontBold llFItalic = toInLine.Characters[lnNdx].FontItalic lnFColor = toInLine.Characters[lnNdx].FontColor lcFName = toInLine.Characters[lnNdx].FontName lnFSize = toInLine.Characters[lnNdx].FontSize lcULine = toInLine.Characters[lnNdx].Underline llStrkThr = toInLine.Characters[lnNdx].StrikeThru lcFVPos = ICASE(toInLine.Characters[lnNdx].SubScript, FONT_VERTICAL_SUBSCRIPT, toInLine.Characters[lnNdx].SuperScript, FONT_VERTICAL_SUPERSCRIPT, FONT_VERTICAL_BASELINE) INSERT INTO xl_strformat (workbook, id, index, stringxml, stringval, fbold, fitalic, fcolor, fname, fsize, uline, strkthr, fvpos, theme, tint, indexed) ; VALUES (toInLine.Workbook, toInLine.StringId, lnNdx, this.GetXMLString(lcRText), lcRText, llFBold, llFItalic, lnFColor, lcFName, lnFSize, lcULine, ; llStrkThr, lcFVPos, 0, 0, 0) ENDFOR IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE setcellnumberdecimals && Sets the number of decimals to display LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnNumDecimals LOCAL lcAlias IF PCOUNT() < 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF VARTYPE(tnNumDecimals) != 'N' .OR. tnNumDecimals < 0 RETURN False ENDIF lcAlias = ALIAS() IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.numdec WITH tnNumDecimals IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, nbrfmtid, numdec, celldeleted) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, 0, tnNumDecimals, False) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ENDPROC PROCEDURE setcellnumberformat && Sets the cell number format LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnNumFormat LOCAL llReturn, lnNumFmtId, lcAlias, loException IF PCOUNT() < 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF VARTYPE(tnNumFormat) != 'N' RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) DO CASE CASE tnNumFormat < START_NUMERIC_FORMAT_ID lnNumFmtId = tnNumFormat CASE tnNumFormat >= START_NUMERIC_FORMAT_ID IF SEEK(BINTOC(tnWB)+BINTOC(tnNumFormat), "xl_numfmts", "id") lnNumFmtId = xl_numfmts.id ELSE IF !this.AddClassDefinedNumericFormats(tnWB, tnNumFormat) RETURN False ENDIF lnNumFmtId = tnNumFormat ENDIF OTHERWISE RETURN False ENDCASE IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, lnNumFmtId, xl_cellxfs.fontid, xl_cellxfs.fillid, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE TRY REPLACE xl_cellxfs.numFmtId WITH lnNumFmtId IN xl_cellxfs CATCH TO loException SET STEP ON ENDTRY ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, lnNumFmtId, 0, 0, 0, "", "", 0, 0, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, lnNumFmtId, 0, 0, 0, "", "", 0, 0, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellnumberformatrange && Sets the number format for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tnNumFormat LOCAL lnRow, lnCol, llReturn IF PCOUNT() < 7 .OR. this.IsCellReferenceInvalid(tnBegRow, tnBegCol) .OR. this.IsCellReferenceInvalid(tnEndRow, tnEndCol) RETURN False ENDIF IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN False ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF !this.SetCellNumberFormat(tnWB, tnSheet, lnRow, lnCol, tnNumFormat) llReturn = False EXIT ENDIF ENDFOR ENDFOR RETURN llReturn ENDPROC PROCEDURE setcellstyle && Sets the cell style LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnCellXfsId IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.cellxfs WITH tnCellXfsId IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, tnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, lnRow, lnCol) ENDIF RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE setcellstylerange && Sets the cell style for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tnCellXfsId LOCAL lnRow, lnCol IF PCOUNT() < 7 .OR. tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN False ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(tnCellXfsId), "xl_cellxfs", "id") FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF this.GetCellRecord(tnWB, tnSheet, lnRow, lnCol) REPLACE xl_cells.cellxfs WITH tnCellXfsId IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, lnRow, lnCol, DATA_TYPE_NONE, tnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, lnRow, lnCol) ENDIF ENDFOR ENDFOR RETURN True ELSE RETURN False ENDIF ENDPROC PROCEDURE setcelltextrotation && Sets the cell text rotation value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnRotation LOCAL lnCellXfsId, lcAlias IF PCOUNT() != 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF VARTYPE(tnRotation) != 'N' RETURN False ENDIF IF !BETWEEN(tnRotation, -90, 90) RETURN False ENDIF lcAlias = ALIAS() tnRotation = FLOOR(tnRotation) IF tnRotation < 0 tnRotation = 90 - tnRotation ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontid, xl_cellxfs.fillid, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, xl_cellxfs.wraptext, tnRotation) ELSE REPLACE xl_cellxfs.rotation WITH tnRotation IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", "", 0, 0, tnRotation) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", "", 0, 0, tnRotation) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ENDPROC PROCEDURE setcellvalidation && Adds a cell validation LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tnType, tnStyle, tnOperator, tlAllowBlank, tlShowInputMsg, tlShowErrMsg, tcErrMsg, tcErrTitle, tcPrompt, tcFormula1, tcFormula2 LOCAL lcAlias, lnIndex, llFormula lcAlias = ALIAS() IF PCOUNT() < 14 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF IF !BETWEEN(tnType, 0, CUSTOM_VALID_TYPE) RETURN False ENDIF IF VARTYPE(tcFormula1) != "C" tcFormula1 = TRANSFORM(tcFormula1) ENDIF IF EMPTY(tcFormula1) .OR. LEN(tcFormula1) > 254 RETURN False ENDIF IF LEFT(tcFormula1, 1) = "=" llFormula = True tcFormula1 = ALLTRIM(SUBSTR(tcFormula1, 2)) ELSE llFormula = False ENDIF IF PCOUNT() < 15 tcFormula2 = "" ENDIF IF VARTYPE(tcFormula2) != "C" tcFormula2 = TRANSFORM(tcFormula2) ENDIF IF LEN(tcFormula2) > 254 RETURN False ENDIF IF LEFT(tcFormula2, 1) = "=" tcFormula2 = ALLTRIM(SUBSTR(tcFormula2, 2)) ENDIF IF VARTYPE(tnStyle) = "N" IF !BETWEEN(tnStyle, 0, INFO_VALID_STYLE) RETURN False ENDIF ELSE tnStyle = 0 ENDIF IF VARTYPE(tnOperator) = "N" IF !BETWEEN(tnOperator, 0, GREATOREQUAL_VALID_OPER) RETURN False ENDIF ELSE tnOperator = 0 ENDIF IF VARTYPE(tcErrMsg) != "C" tcErrMsg = "" ENDIF IF VARTYPE(tcErrTitle) != "C" tcErrTitle = "" ENDIF IF VARTYPE(tcPrompt) != "C" tcPrompt = "" ENDIF IF VARTYPE(tlAllowBlank) != "L" tlAllowBlank = True ENDIF IF VARTYPE(tlShowInputMsg) != "L" tlShowInputMsg = True ENDIF IF VARTYPE(tlShowErrMsg) != "L" tlShowErrMsg = True ENDIF *-* Check if the cell is part of a merged range of cells; if so set the cell to the upper left cell of the merged range IF RECCOUNT('xl_mergecells') > 0 SELECT xl_mergecells LOCATE FOR workbook = tnWB .AND. sheet = tnSheet .AND. BETWEEN(tnCellRow, begrow, endrow) .AND. BETWEEN(tnCellCol, begcol, endcol) .AND. !DELETED() IF FOUND() tnCellRow = xl_mergecells.begrow tnCellCol = xl_mergecells.begcol ENDIF ENDIF SELECT xl_validation LOCATE FOR BINTOC(workbook)+BINTOC(sheet) = BINTOC(tnWB)+BINTOC(tnSheet) ; .AND. UPPER(formula1) = UPPER(PADR(tcFormula1, 240)) ; .AND. UPPER(formula2) = UPPER(PADR(tcFormula2, 240)) .AND. !DELETED() IF FOUND() lnIndex = 0 DO WHILE FOUND() IF xl_validation.vtype = tnType ; .AND. xl_validation.vstyle = tnStyle ; .AND. xl_validation.voperator = tnOperator ; .AND. xl_validation.errmsg = tcErrMsg ; .AND. xl_validation.errtitle = tcErrTitle ; .AND. xl_validation.allowblank = tlAllowBlank ; .AND. xl_validation.showinpmsg = tlShowInputMsg ; .AND. xl_validation.showerrmsg = tlShowErrMsg ; .AND. xl_validation.vprompt = tcPrompt lnIndex = xl_validation.validndx EXIT ENDIF CONTINUE ENDDO IF lnIndex = 0 INSERT INTO xl_validation (workbook, sheet, vtype, vstyle, voperator, errmsg, errtitle, vprompt, allowblank, showinpmsg, showerrmsg, formula, formula1, formula2) ; VALUES (tnWB, tnSheet, tnType, tnStyle, tnOperator, tcErrMsg, tcErrTitle, tcPrompt, tlAllowBlank, tlShowInputMsg, tlShowErrMsg, llFormula, tcFormula1, tcFormula2) lnIndex = xl_validation.validndx ENDIF ELSE INSERT INTO xl_validation (workbook, sheet, vtype, vstyle, voperator, errmsg, errtitle, vprompt, allowblank, showinpmsg, showerrmsg, formula, formula1, formula2) ; VALUES (tnWB, tnSheet, tnType, tnStyle, tnOperator, tcErrMsg, tcErrTitle, tcPrompt, tlAllowBlank, tlShowInputMsg, tlShowErrMsg, llFormula, tcFormula1, tcFormula2) lnIndex = xl_validation.validndx ENDIF IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) REPLACE xl_cells.validndx WITH lnIndex IN xl_cells ELSE INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, 0, False, -1, lnIndex) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ENDPROC PROCEDURE setcellvalue && Sets the cell value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, txCellValue LOCAL lcCellValue, lcDataType, lnStringNdx, lnSetDecimals, lnWholePart, lnFractPart, lcAlias, lnNumFmtId, lcHorzAlign LOCAL lcSetDate, lcSetPoint, lcSeparator, lcCurrency IF PCOUNT() < 5 .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() *-* Check if the cell is part of a merged range of cells; if so set the cell to the upper left cell of the merged range IF RECCOUNT('xl_mergecells') > 0 SELECT xl_mergecells LOCATE FOR workbook = tnWB .AND. sheet = tnSheet .AND. tnCellRow >= begrow .AND. tnCellRow <= endrow .AND. tnCellCol >= begcol .AND. tnCellCol <= endcol .AND. !DELETED() IF FOUND() tnCellRow = xl_mergecells.begrow tnCellCol = xl_mergecells.begcol ENDIF ENDIF *-* Assign the data type based on type of value and add to cell lnStringNdx = 0 lcHorzAlign = "" lnNumFmtId = 0 lcSetPoint = SET("POINT") lcSeparator = SET("SEPARATOR") IF lcSetPoint != "." && Change recommended by Doug Hennig; 2017-06-12 SET POINT TO "." SET SEPARATOR TO "," ENDIF DO CASE CASE VARTYPE(txCellValue) = DATA_TYPE_LOGICAL lcDataType = DATA_TYPE_LOGICAL lcCellValue = "StringValue" txCellValue = IIF(txCellValue, GETWORDNUM(this.TrueFalseValue, 1, "|"), GETWORDNUM(this.TrueFalseValue, 2, "|")) lnStringNdx = this.AddStringValue(tnWB, txCellValue, False) CASE VARTYPE(txCellValue) = DATA_TYPE_CHAR txCellValue = ALLTRIM(txCellValue) IF LEN(txCellValue) > LIMITS_MAX_CELL_CHARS RETURN False ENDIF lcDataType = DATA_TYPE_CHAR lcCellValue = "StringValue" lnStringNdx = this.AddStringValue(tnWB, txCellValue, False) DELETE FOR workbook = tnWB .AND. id = lnStringNdx IN xl_strformat CASE VARTYPE(txCellValue) = DATA_TYPE_DATE IF txCellValue >= DATE(1900, 1, 1) lcDataType = DATA_TYPE_DATE lcCellValue = TRANSFORM(INT(txCellValue - DATE(1900, 1, 1) + 2)) ELSE lcDataType = DATA_TYPE_CHAR lcCellValue = "StringValue" lcSetDate = SET("DATE") SET DATE TO AMERICAN lnStringNdx = this.AddStringValue(tnWB, TRANSFORM(txCellValue), False) SET DATE TO (lcSetDate) ENDIF lcHorzAlign = CELL_HORIZ_ALIGN_LEFT lnNumFmtId = CELL_FORMAT_DATE_MMDDYY CASE VARTYPE(txCellValue) = DATA_TYPE_DATETIME IF TTOD(txCellValue) >= DATE(1900, 1, 1) lnSetDecimals = SET("DECIMALS") SET DECIMALS TO 12 lcDataType = DATA_TYPE_DATETIME lnWholePart = INT(TTOD(txCellValue) - DATE(1900, 1, 1) + 2) lnFractPart = ((HOUR(txCellValue) * 60 + MINUTE(txCellValue)) * 60 + SEC(txCellValue)) / (24 * 60 * 60) lcCellValue = TRANSFORM(lnWholePart + lnFractPart) SET DECIMALS TO (lnSetDecimals) ELSE lcDataType = DATA_TYPE_CHAR lcCellValue = "StringValue" lcSetDate = SET("DATE") SET DATE TO AMERICAN lnStringNdx = this.AddStringValue(tnWB, TRANSFORM(txCellValue), False) SET DATE TO (lcSetDate) ENDIF lcHorzAlign = CELL_HORIZ_ALIGN_LEFT lnNumFmtId = CELL_FORMAT_DATETIME_MMMDDYYYY_TTAM CASE VARTYPE(txCellValue) = DATA_TYPE_FLOAT lcCellValue = TRANSFORM(txCellValue) IF ATC(".", lcCellValue) > 0 lcDataType = DATA_TYPE_FLOAT ELSE lcDataType = DATA_TYPE_INT ENDIF CASE VARTYPE(txCellValue) = DATA_TYPE_CURRENCY IF this.SaveCurrencyAsNumeric lcDataType = DATA_TYPE_FLOAT && Change requested by Tony Federer lcCellValue = TRANSFORM(MTON(txCellValue)) ELSE lcCurrency = SET("Currency", 1) lcCellValue = CHRTRAN(TRANSFORM(txCellValue), lcCurrency+",", "") lcDataType = DATA_TYPE_CURRENCY lcHorzAlign = CELL_HORIZ_ALIGN_RIGHT DO CASE CASE lcCurrency = "£" lnNumFmtId = CELL_FORMAT_ACC_CURR_POUNDS CASE lcCurrency = "€" lnNumFmtId = CELL_FORMAT_ACC_CURR_EURO OTHERWISE lnNumFmtId = CELL_FORMAT_CURRENCY_PAREN ENDCASE ENDIF CASE VARTYPE(txCellValue) = DATA_TYPE_GENERAL lcDataType = DATA_TYPE_GENERAL lcCellValue = "" && Change recommendation by Doug Hennig OTHERWISE lcDataType = DATA_TYPE_GENERAL lcCellValue = TRANSFORM(txCellValue) ENDCASE IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, lnNumFmtId, xl_cellxfs.fontid, xl_cellxfs.fillid, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, xl_cellxfs.wraptext, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.numFmtId WITH lnNumFmtId IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, lnNumFmtId, 0, 0, 0, "", "", 0, 0, 0) ENDIF REPLACE xl_cells.cellvalue WITH lcCellValue, ; xl_cells.cellxfs WITH lnCellXfsId, ; xl_cells.cellformula WITH "", ; xl_cells.stringid WITH lnStringNdx, ; xl_cells.datatype WITH lcDataType, ; xl_cells.celldeleted WITH False IN xl_cells ELSE IF lnNumFmtId > 0 lnCellXfsId = this.GetCellXfsId(tnWB, lnNumFmtId, 0, 0, 0, "", "", 0, 0, 0) ELSE lnCellXfsId = 0 ENDIF INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, cellvalue, stringid, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, lcCellValue, lnStringNdx, lcDataType, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF IF lcSetPoint != "." && Change recommended by Doug Hennig; 2017-06-12 SET POINT TO (lcSetPoint) SET SEPARATOR TO (lcSeparator) ENDIF RETURN True ENDPROC PROCEDURE setcellwordwrap && Sets the cell word-wrapping value LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol, tlWordWrap LOCAL llReturn, lnWrapText, lnCellXfsId, lcAlias IF PCOUNT() < 5 .OR. VARTYPE(tlWordWrap) != "L" .OR. this.IsCellReferenceInvalid(tnCellRow, tnCellCol) RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) lnWrapText = IIF(tlWordWrap, 1, 0) *-* Set the XfsId to the cell record IF this.GetCellRecord(tnWB, tnSheet, tnCellRow, tnCellCol) IF xl_cells.cellxfs > 0 .AND. this.GetCellXfsRecord(tnWB, xl_cells.cellxfs) lnCellXfsId = xl_cellxfs.id SELECT workbook FROM xl_cells WHERE workbook = tnWB AND cellxfs = lnCellXfsId INTO CURSOR xl_temp IF _TALLY > 1 lnCellXfsId = this.GetCellXfsId(tnWB, xl_cellxfs.numFmtId, xl_cellxfs.fontId, xl_cellxfs.fillid, xl_cellxfs.borderId, xl_cellxfs.halign, xl_cellxfs.valign, xl_cellxfs.indent, lnWrapText, xl_cellxfs.rotation) ELSE REPLACE xl_cellxfs.wraptext WITH lnWrapText IN xl_cellxfs ENDIF USE IN SELECT('xl_temp') ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", "", 0, lnWrapText, 0) ENDIF REPLACE xl_cells.cellxfs WITH lnCellXfsId IN xl_cells ELSE lnCellXfsId = this.GetCellXfsId(tnWB, 0, 0, 0, 0, "", "", 0, lnWrapText, 0) INSERT INTO xl_cells (workbook, sheet, cellrow, cellcol, datatype, cellxfs, celldeleted, numdec, validndx) ; VALUES (tnWB, tnSheet, tnCellRow, tnCellCol, DATA_TYPE_NONE, lnCellXfsId, False, -1, 0) this.SetRowMaxColumn(tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcellwordwraprange && Sets the word wrap for a range of cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol, tlWordWrap LOCAL lnRow, lnCol, llReturn IF PCOUNT() < 7 .OR. VARTYPE(tlWordWrap) != "L" .OR. this.IsCellReferenceInvalid(tnBegRow, tnBegCol) .OR. this.IsCellReferenceInvalid(tnEndRow, tnEndCol) RETURN False ENDIF IF tnBegRow > tnEndRow .OR. tnBegCol > tnEndCol RETURN False ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow FOR lnCol=tnBegCol TO tnEndCol IF !this.SetCellWordWrap(tnWB, tnSheet, lnRow, lnCol, tlWordWrap) llReturn = False EXIT ENDIF ENDFOR ENDFOR RETURN llReturn ENDPROC PROCEDURE setcolumnbestfit && Set the column to best fit LPARAMETERS tnWB, tnSheet, tnColumn, tlBestFit LOCAL llReturn, lcAlias IF PCOUNT() < 4 RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF SEEK(this.GetColWidthKeyExpr(tnWB, tnSheet, tnColumn), "xl_colwidths", "shcolumn") REPLACE xl_colwidths.bestfit WITH tlBestFit IN xl_colwidths ELSE INSERT INTO xl_colwidths (workbook, sheet, column, bestfit) VALUES (tnWB, tnSheet, tnColumn, tlBestFit) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcolumnwidth && Sets the column width LPARAMETERS tnWB, tnSheet, tnColumn, tnWidth LOCAL llReturn, lcAlias IF PCOUNT() < 4 .OR. VARTYPE(tnWidth) != "N" RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF SEEK(this.GetColWidthKeyExpr(tnWB, tnSheet, tnColumn), "xl_colwidths", "shcolumn") REPLACE xl_colwidths.width WITH tnWidth IN xl_colwidths ELSE INSERT INTO xl_colwidths (workbook, sheet, column, width, bestfit) VALUES (tnWB, tnSheet, tnColumn, tnWidth, False) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setcolumnwidthrange && Sets the column width for a range of columns LPARAMETERS tnWB, tnSheet, tnBegCol, tnEndCol, tnWidth LOCAL lnCol, llReturn IF PCOUNT() < 5 RETURN False ENDIF IF tnBegCol > tnEndCol RETURN False ENDIF llReturn = True FOR lnCol=tnBegCol TO tnEndCol IF !this.SetColumnWidth(tnWB, tnSheet, lnCol, tnWidth) llReturn = False EXIT ENDIF ENDFOR RETURN llReturn ENDPROC PROCEDURE setcustompapersize && Sets the paper size based on custom dimensions LPARAMETERS tnWB, tnSheet, tnWidth, tnHeight, tcDimen LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 5 .AND. this.GetSheetRecord(tnWB, tnSheet) DO CASE CASE tnWidth=0 .OR. tnHeight=0 REPLACE xl_sheets.paperwidth WITH 0, ; xl_sheets.paperheight WITH 0, ; xl_sheets.paperdimen WITH "" IN xl_sheets llReturn = True CASE tnWidth>0 .AND. tnHeight>0 .AND. INLIST(tcDimen, "mm", "in") REPLACE xl_sheets.paperwidth WITH tnWidth, ; xl_sheets.paperheight WITH tnHeight, ; xl_sheets.paperdimen WITH LOWER(tcDimen) IN xl_sheets llReturn = True OTHERWISE llReturn = False ENDCASE ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setdefaultborder && Sets the default border style for the workbook LPARAMETERS tnWB, tcLStyle, tnLColor, tcRStyle, tnRColor, tcTStyle, tnTColor, tcBStyle, tnBColor, tcDStyle, tnDColor, tnDiagDn, tnDiagUp LOCAL lcAlias IF PCOUNT() < 2 RETURN False ENDIF IF VARTYPE(tcLStyle) != "C" tcLStyle = BORDER_STYLE_NONE ENDIF lcAlias = ALIAS() DO CASE CASE PCOUNT() = 2 tnLColor = 0 tcRStyle = tcLStyle tnRColor = 0 tcTStyle = tcLStyle tnTColor = 0 tcBStyle = tcLStyle tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 3 tcRStyle = tcLStyle tnRColor = 0 tcTStyle = tcLStyle tnTColor = 0 tcBStyle = tcLStyle tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 4 tnRColor = 0 tcTStyle = tcLStyle tnTColor = 0 tcBStyle = tcLStyle tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 5 tcTStyle = tcLStyle tnTColor = 0 tcBStyle = tcLStyle tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 6 tnTColor = 0 tcBStyle = tcLStyle tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 7 tcBStyle = tcLStyle tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 8 tnBColor = 0 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 9 tcDStyle = tcLStyle tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 10 tnDColor = 0 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 11 tnDiagDn = 0 tnDiagUp = 0 CASE PCOUNT() = 12 tnDiagUp = 0 ENDCASE IF VARTYPE(tnLColor) != "N" tnLColor = 0 ENDIF IF VARTYPE(tcRStyle) != "C" tcRStyle = tcLStyle ENDIF IF VARTYPE(tnRColor) != "N" tnRColor = 0 ENDIF IF VARTYPE(tcTStyle) != "C" tcTStyle = tcLStyle ENDIF IF VARTYPE(tnTColor) != "N" tnTColor = 0 ENDIF IF VARTYPE(tcBStyle) != "C" tcBStyle = tcLStyle ENDIF IF VARTYPE(tnBColor) != "N" tnBColor = 0 ENDIF IF VARTYPE(tcDStyle) != "C" tcDStyle = tcLStyle ENDIF IF VARTYPE(tnDColor) != "N" tnDColor = 0 ENDIF IF VARTYPE(tnDiagDn) != "N" tnDiagDn = 0 ENDIF IF VARTYPE(tnDiagUp) != "N" tnDiagUp = 0 ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(0), "xl_borders", "id") REPLACE xl_borders.lstyle WITH tcLStyle, ; xl_borders.lcolor WITH tnLColor, ; xl_borders.rstyle WITH tcRStyle, ; xl_borders.rcolor WITH tnRColor, ; xl_borders.tstyle WITH tcTStyle, ; xl_borders.tcolor WITH tnTColor, ; xl_borders.bstyle WITH tcBStyle, ; xl_borders.bcolor WITH tnBColor, ; xl_borders.dstyle WITH tcDStyle, ; xl_borders.dcolor WITH tnDColor, ; xl_borders.diagdn WITH tnDiagDn, ; xl_borders.diagup WITH tnDiagUp IN xl_borders ELSE INSERT INTO xl_borders (workbook, id, lstyle, lcolor, rstyle, rcolor, tstyle, tcolor, bstyle, bcolor, dstyle, dcolor, diagdn, diagup) ; VALUES (tnWB, 0, tcLStyle, tnLColor, tcRStyle, tnRColor, tcTStyle, tnTColor, tcBStyle, tnBColor, tcDStyle, tnDColor, tnDiagDn, tnDiagUp) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ENDPROC PROCEDURE setdefaultfill && Sets the default fill for the workbook LPARAMETERS tnWB, tcPatternType, tnFColor, tnBColor LOCAL lnFIndex, lnBIndex, lcAlias IF PCOUNT() < 2 RETURN False ENDIF lcAlias = ALIAS() IF VARTYPE(tcPatternType) != "C" tcPatternType = FILL_STYLE_NONE ENDIF DO CASE CASE PCOUNT() = 2 tnFColor = 0 lnFIndex = 0 tnBColor = 0 lnBIndex = 0 CASE PCOUNT() = 3 tnBColor = 0 lnBIndex = 64 ENDCASE IF VARTYPE(tnFColor) != "N" tnFColor = 0 ENDIF IF VARTYPE(tnBColor) != "N" tnBColor = RGB(255,255,255) ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(0), "xl_fills", "id") REPLACE xl_fills.fgcolor WITH tnFColor, ; xl_fills.bgcolor WITH tnBColor, ; xl_fills.patttype WITH tcPatternType, ; xl_fills.theme WITH 0, ; xl_fills.tint WITH 0, ; xl_fills.fgindexed WITH 0, ; xl_fills.bgindexed WITH 0 IN xl_fills ELSE INSERT INTO xl_fills (workbook, id, fgcolor, bgcolor, patttype, theme, tint, fgindexed, bgindexed) ; VALUES (tnWB, 0, tnFColor, tnBColor, tcPatternType, 0, 0, lnFIndex, lnBIndex) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN True ENDPROC PROCEDURE setdefaultfont && Sets the default font for the workbook LPARAMETERS tnWB, tcFontName, tnSize, tlBold, tlItalic, tnColor, tcUline, tlStrkthr, tcFVPos, tnTheme, tnTint, tnIndexed LOCAL lcAlias IF PCOUNT() < 2 RETURN False ENDIF lcAlias = ALIAS() DO CASE CASE PCOUNT() = 2 tnSize = 11 tlBold = False tlItalic = False tnColor = 0 tcUline = "" tlStrkthr = False tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 3 tlBold = False tlItalic = False tnColor = 0 tcUline = "" tlStrkthr = False tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 4 tlItalic = False tnColor = 0 tcUline = "" tlStrkthr = False tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 5 tnColor = 0 tcUline = "" tlStrkthr = False tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 6 tcUline = "" tlStrkthr = False tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 7 tlStrkthr = False tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 8 tcFVPos = "" tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 9 tnTheme = 0 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 10 tnTint = 0 tnIndexed = 0 CASE PCOUNT() = 11 tnIndexed = 0 ENDCASE IF VARTYPE(tcFontName) != "C" tcFontName = "Calibri" ENDIF IF VARTYPE(tnSize) != "N" tnSize = 11 ENDIF IF VARTYPE(tlBold) != "L" tlBold = False ENDIF IF VARTYPE(tlItalic) != "L" tlItalic = False ENDIF IF VARTYPE(tnColor) != "N" tnColor = 0 ENDIF IF VARTYPE(tcUline) != "C" tcUline = "" ENDIF IF VARTYPE(tlStrkthr) != "L" tlStrkthr = False ENDIF IF VARTYPE(tcFVPos) != "C" tcFVPos = "" ENDIF IF VARTYPE(tnTheme) != "N" tnTheme = 0 ENDIF IF VARTYPE(tnTint) != "N" tnTint = 0 ENDIF IF VARTYPE(tnIndexed) != "N" tnTint = 0 ENDIF IF SEEK(BINTOC(tnWB)+BINTOC(0), "xl_fonts", "id") REPLACE xl_fonts.fname WITH tcFontName, ; xl_fonts.fsize WITH tnSize, ; xl_fonts.fbold WITH tlBold, ; xl_fonts.fitalic WITH tlItalic, ; xl_fonts.fcolor WITH tnColo , ; xl_fonts.uline WITH tcUline, ; xl_fonts.strkthr WITH tlStrkthr, ; xl_fonts.fvpos WITH tcFVPos, ; xl_fonts.theme WITH tnTheme, ; xl_fonts.tint WITH tnTint, ; xl_fonts.indexed WITH tnIndexed IN xl_fonts ELSE INSERT INTO xl_fonts (workbook, id, fname, fsize, fbold, fitalic, fcolor, uline, strkthr, fvpos, theme, tint, indexed) ; VALUES (tnWB, 0, tcFontName, tnSize, tlBold, tlItalic, tnColor, tcUline, tlStrkthr, tcFVPos, tnTheme, tnTint, tnIndexed) ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN true ENDPROC PROCEDURE setheaderfootersetup && Sets the header and footer setup for the sheet LPARAMETERS tnWB, tnSheet, tlAlignMargin, tlDiffFirstPg, tlDiffOddEven, tlScaleWDoc LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 6 .AND. this.GetSheetRecord(tnWB, tnSheet) IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet), "xl_hdrfooterdefn", "wbsheet") REPLACE xl_hdrfooterdefn.alignmargin WITH tlAlignMargin, ; xl_hdrfooterdefn.difffirstpg WITH tlDiffFirstPg, ; xl_hdrfooterdefn.diffoddeven WITH tlDiffOddEven, ; xl_hdrfooterdefn.scalewdoc WITH tlScaleWDoc IN xl_hdrfooterdefn ELSE INSERT INTO xl_hdrfooterdefn (workbook, sheet, alignmargin, difffirstpg, diffoddeven, scalewdoc) ; VALUES (tnWB, tnSheet, tlAlignMargin, tlDiffFirstPg, tlDiffOddEven, tlScaleWDoc) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setheaderfootertext && Sets the header/footer text for the sheet LPARAMETERS tnWB, tnSheet, tnPage, tnSection, tcText, tcFontName, tnFontSize, tnFontEffect, tnFontColor LOCAL llReturn, lcAlias DO CASE CASE PCOUNT() < 5 RETURN False CASE PCOUNT() = 5 tcFontName = "" tnFontSize = 0 tnFontEffect = 0 tnFontColor = 0 CASE PCOUNT() = 6 tnFontSize = 0 tnFontEffect = 0 tnFontColor = 0 CASE PCOUNT() = 7 tnFontEffect = 0 tnFontColor = 0 CASE PCOUNT() = 8 tnFontColor = 0 ENDCASE IF VARTYPE(tcFontName) != "C" tcFontName = "" ENDIF IF VARTYPE(tnFontSize) != "N" tnFontSize = 0 ENDIF IF VARTYPE(tnFontEffect) != "N" tnFontEffect = 0 ENDIF IF VARTYPE(tnFontColor) != "N" tnFontColor = 0 ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet), "xl_hdrfooterdefn", "wbsheet") IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, tnSheet, tnPage, tnSection), "xl_hdrfootertext", "hdrfootr") REPLACE xl_hdrfootertext.text WITH tcText, ; xl_hdrfootertext.fontname WITH tcFontName, ; xl_hdrfootertext.fontsize WITH tnFontSize, ; xl_hdrfootertext.fontstyle WITH tnFontEffect, ; xl_hdrfootertext.fontcolor WITH tnFontColor IN xl_hdrfootertext ELSE INSERT INTO xl_hdrfootertext (workbook, sheet, page, section, text, fontname, fontsize, fontstyle, fontcolor) ; VALUES (tnWB, tnSheet, tnPage, tnSection, tcText, tcFontName, tnFontSize, tnFontEffect, tnFontColor) ENDIF llReturn = True ELSE llReturn = False ENDIF ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROTECTED PROCEDURE setlastid && Sets the last used Id Value for strings, borders, fills, fonts, and cellxfs LPARAMETERS tnWB, tnLastId, tcCursor LOCAL lnNdx DO CASE CASE tcCursor = "xl_borders" lnNdx = ASCAN(this.LastBorderId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastBorderId[lnNdx, 2] = tnLastId ELSE IF this.LastBorderId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastBorderId, 1) + 1 ENDIF DIMENSION this.LastBorderId[lnNdx, 2] this.LastBorderId[lnNdx, 1] = tnWB this.LastBorderId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_cellxfs" lnNdx = ASCAN(this.LastCellXfsId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastCellXfsId[lnNdx, 2] = tnLastId ELSE IF this.LastCellXfsId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastCellXfsId, 1) + 1 ENDIF DIMENSION this.LastCellXfsId[lnNdx, 2] this.LastCellXfsId[lnNdx, 1] = tnWB this.LastCellXfsId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_fills" lnNdx = ASCAN(this.LastFillId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastFillId[lnNdx, 2] = tnLastId ELSE IF this.LastFillId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastFillId, 1) + 1 ENDIF DIMENSION this.LastFillId[lnNdx, 2] this.LastFillId[lnNdx, 1] = tnWB this.LastFillId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_fonts" lnNdx = ASCAN(this.LastFontId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastFontId[lnNdx, 2] = tnLastId ELSE IF this.LastFontId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastFontId, 1) + 1 ENDIF DIMENSION this.LastFontId[lnNdx, 2] this.LastFontId[lnNdx, 1] = tnWB this.LastFontId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_ndxcolors" lnNdx = ASCAN(this.LastIndexColorId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastIndexColorId[lnNdx, 2] = tnLastId ELSE IF this.LastIndexColorId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastIndexColorId, 1) + 1 ENDIF DIMENSION this.LastIndexColorId[lnNdx, 2] this.LastIndexColorId[lnNdx, 1] = tnWB this.LastIndexColorId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_mrucolors" lnNdx = ASCAN(this.LastMruColorId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastMruColorId[lnNdx, 2] = tnLastId ELSE IF this.LastMruColorId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastMruColorId, 1) + 1 ENDIF DIMENSION this.LastMruColorId[lnNdx, 2] this.LastMruColorId[lnNdx, 1] = tnWB this.LastMruColorId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_numfmts" lnNdx = ASCAN(this.LastNumFmtId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastNumFmtId[lnNdx, 2] = tnLastId ELSE IF this.LastNumFmtId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastNumFmtId, 1) + 1 ENDIF DIMENSION this.LastNumFmtId[lnNdx, 2] this.LastNumFmtId[lnNdx, 1] = tnWB this.LastNumFmtId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_relationships" lnNdx = ASCAN(this.LastRelationId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastRelationId[lnNdx, 2] = tnLastId ELSE IF this.LastRelationId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastRelationId, 1) + 1 ENDIF DIMENSION this.LastRelationId[lnNdx, 2] this.LastRelationId[lnNdx, 1] = tnWB this.LastRelationId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_sheets" lnNdx = ASCAN(this.LastSheetId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastSheetId[lnNdx, 2] = tnLastId ELSE IF this.LastSheetId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastSheetId, 1) + 1 ENDIF DIMENSION this.LastSheetId[lnNdx, 2] this.LastSheetId[lnNdx, 1] = tnWB this.LastSheetId[lnNdx, 2] = tnLastId ENDIF CASE tcCursor = "xl_strings" lnNdx = ASCAN(this.LastStringId, tnWB, 1, -1, 1, 15) IF lnNdx > 0 this.LastStringId[lnNdx, 2] = tnLastId ELSE IF this.LastStringId[1, 1] = 0 lnNdx = 1 ELSE lnNdx = ALEN(this.LastStringId, 1) + 1 ENDIF DIMENSION this.LastStringId[lnNdx, 2] this.LastStringId[lnNdx, 1] = tnWB this.LastStringId[lnNdx, 2] = tnLastId ENDIF ENDCASE ENDPROC PROCEDURE setpapersize && Sets the paper size for the selected sheet LPARAMETERS tnWB, tnSheet, tnPaperSize LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 3 .AND. this.GetSheetRecord(tnWB, tnSheet) IF BETWEEN(tnPaperSize, 0, 118) REPLACE xl_sheets.papersize WITH tnPaperSize IN xl_sheets llReturn = True ELSE llReturn = False ENDIF ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setprintfittoheight && Number of vertical pages to fit on for printing LPARAMETERS tnWB, tnSheet, tnFitToHeight LOCAL llReturn lcAlias = ALIAS() IF PCOUNT() = 3 .AND. this.GetSheetRecord(tnWB, tnSheet) IF INT(tnFitToHeight) >= 0 REPLACE xl_sheets.fittoheight WITH INT(tnFitToHeight) IN xl_sheets llReturn = True ELSE llReturn = False ENDIF ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setprintfittowidth && Number of horizontal pages to fit on for printing LPARAMETERS tnWB, tnSheet, tnFitToWidth LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 3 .AND. this.GetSheetRecord(tnWB, tnSheet) IF INT(tnFitToWidth) >= 0 REPLACE xl_sheets.fittowidth WITH INT(tnFitToWidth) IN xl_sheets llReturn = True ELSE llReturn = False ENDIF ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setprintorientation && Sets the printer orientation for sheet output LPARAMETERS tnWB, tnSheet, tnOrientation LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 3 .AND. this.GetSheetRecord(tnWB, tnSheet) REPLACE xl_sheets.prnorient WITH tnOrientation IN xl_sheets llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setrowheight && Sets the row height LPARAMETERS tnWB, tnSheet, tnRow, tnHeight LOCAL llReturn, lcAlias IF PCOUNT() < 4 .OR. VARTYPE(tnHeight) != "N" RETURN False ENDIF lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) IF SEEK(this.GetRowHeightKeyExpr(tnWB, tnSheet, tnRow), "xl_rowheights", "shrow") REPLACE xl_rowheights.height WITH tnHeight IN xl_rowheights ELSE INSERT INTO xl_rowheights (workbook, sheet, row, height) VALUES (tnWB, tnSheet, tnRow, tnHeight) ENDIF llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setrowheightrange && Sets the row height for a range of rows LPARAMETERS tnWB, tnSheet, tnBegRow, tnEndRow, tnHeight LOCAL lnRow, llReturn IF PCOUNT() < 5 RETURN False ENDIF IF tnBegRow > tnEndRow RETURN False ENDIF llReturn = True FOR lnRow=tnBegRow TO tnEndRow IF !this.SetRowHeight(tnWB, tnSheet, lnRow, tnHeight) llReturn = False EXIT ENDIF ENDFOR RETURN llReturn ENDPROC PROTECTED PROCEDURE setrowmaxcolumn && Sets the value for the maximum cell column in a row LPARAMETERS tnWB, tnSheet, tnCellRow, tnCellCol IF SEEK(BINTOC(tnWB)+BINTOC(tnSheet)+BINTOC(tnCellRow), "xl_rows", "id") IF xl_rows.maxcol < tnCellCol REPLACE xl_rows.maxcol WITH tnCellCol IN xl_rows ENDIF ELSE INSERT INTO xl_rows (workbook, sheet, row, maxcol) VALUES (tnWB, tnSheet, tnCellRow, tnCellCol) ENDIF ENDPROC PROCEDURE setsheetmargins && Sets the sheet margin values LPARAMETERS tnWB, tnSheet, tnLeft, tnRight, tnTop, tnbot, tnHeader, tnFooter LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 8 .AND. this.GetSheetRecord(tnWB, tnSheet) REPLACE xl_sheets.mleft WITH tnLeft, ; xl_sheets.mright WITH tnRight, ; xl_sheets.mtop WITH tnTop, ; xl_sheets.mbot WITH tnbot, ; xl_sheets.mheader WITH tnHeader, ; xl_sheets.mfooter WITH tnFooter IN xl_sheets llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setsheetscale && Sets the print scale; must be between 10 and 400; i.e. 10=10%, 100=100%, etc. LPARAMETERS tnWB, tnSheet, tnScale LOCAL llReturn, lcAlias lcAlias = ALIAS() IF PCOUNT() = 3 .AND. this.GetSheetRecord(tnWB, tnSheet) IF BETWEEN(INT(tnScale), 10, 400) REPLACE xl_sheets.scale WITH INT(tnScale) IN xl_sheets llReturn = True ELSE llReturn = False ENDIF ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE setsheetvisibility && Sets the sheet visibility LPARAMETERS tnWB, tnSheet, tnVisiblity LOCAL llReturn, lcAlias llReturn = False lcAlias = ALIAS() IF PCOUNT() = 3 .AND. this.GetSheetRecord(tnWB, tnSheet) IF BETWEEN(tnVisiblity, VISIBLE_SHEET_STATE, VERYHIDDEN_SHEET_STATE) REPLACE xl_sheets.state WITH tnVisiblity IN xl_sheets llReturn = True ENDIF ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROTECTED PROCEDURE ttoc3 && Equlivalent of TTOC() function for pre VFP9 support LPARAMETERS ttime LOCAL lct IF PCOUNT() < 1 OR VARTYPE(m.ttime) != "T" RETURN ENDIF lct = TTOC(m.ttime,1) RETURN LEFT(m.lct,4) + "-" + SUBSTR(m.lct,5,2) + "-" + SUBSTR(m.lct,7,2) + "T" + SUBSTR(m.lct,9,2) + ":" + SUBSTR(m.lct,11,2) + ":" + RIGHT(m.lct,2) ENDPROC PROCEDURE unfreezepanes && Removes the pane freeze from the sheet LPARAMETERS tnWB, tnSheet LOCAL llReturn, lcAlias lcAlias = ALIAS() IF this.GetSheetRecord(tnWB, tnSheet) REPLACE xl_sheets.xsplit WITH 0, ; xl_sheets.ysplit WITH 0 IN xl_sheets llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROCEDURE unmergedcells && Unmerges merged cells LPARAMETERS tnWB, tnSheet, tnBegRow, tnBegCol, tnEndRow, tnEndCol LOCAL llReturn, lcAlias lcAlias = ALIAS() SELECT xl_mergecells LOCATE FOR workbook=tnWB .AND. sheet=tnSheet .AND. begrow=tnBegRow .AND. begcol=tnBegCol .AND. endrow=tnEndRow .AND. endcol=tnEndCol .AND. !DELETED() IF FOUND() DELETE IN xl_mergecells llReturn = True ELSE llReturn = False ENDIF IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llReturn ENDPROC PROTECTED PROCEDURE writeasinlineformattedstring && Writes the string as formatted in-line LPARAMETERS thFile, tnRow, tnCol, txCellValue FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '' + this.GetXMLString(txCellValue) + '') FWRITE(thFile, '') FWRITE(thFile, '') FWRITE(thFile, '') ENDPROC PROTECTED PROCEDURE writeasinlinestring && Writes the value as an inlineStr value LPARAMETERS thFile, tnRow, tnCol, txCellValue FWRITE(thFile, '') FWRITE(thFile, '' + this.GetXMLString(txCellValue) + '') FWRITE(thFile, '') ENDPROC PROTECTED PROCEDURE writedirectcellformattedvalue && WriteDirectCellFormattedValue LPARAMETERS thFile, tnRow, tnCol, txCellValue DO CASE CASE ISNULL(txCellValue) RETURN CASE INLIST(VARTYPE(txCellValue), "C", "D", "T") .AND. EMPTY(txCellValue) RETURN CASE VARTYPE(txCellValue) = DATA_TYPE_DATE this.WriteAsInLineFormattedString(thFile, tnRow, tnCol, TRANSFORM(txCellValue)) CASE VARTYPE(txCellValue) = DATA_TYPE_DATETIME this.WriteAsInLineFormattedString(thFile, tnRow, tnCol, TTOC(txCellValue)) CASE VARTYPE(txCellValue) = DATA_TYPE_LOGICAL txCellValue = IIF(txCellValue, GETWORDNUM(this.TrueFalseValue, 1, "|"), GETWORDNUM(this.TrueFalseValue, 2, "|")) this.WriteAsInLineFormattedString(thFile, tnRow, tnCol, txCellValue) CASE VARTYPE(txCellValue) = DATA_TYPE_CURRENCY FWRITE(thFile, '') FWRITE(thFile, '' + TRANSFORM(MTON(txCellValue)) + '') CASE VARTYPE(txCellValue) = DATA_TYPE_CHAR this.WriteAsInLineFormattedString(thFile, tnRow, tnCol, ALLTRIM(txCellValue)) CASE INLIST(VARTYPE(txCellValue), DATA_TYPE_INT, DATA_TYPE_FLOAT) FWRITE(thFile, '') FWRITE(thFile, '' + TRANSFORM(txCellValue) + '') OTHERWISE FWRITE(thFile, '') FWRITE(thFile, 'Unsupported Field Type') ENDCASE ENDPROC PROTECTED PROCEDURE writedirectcellvalue && Writes the cell value directly to the sheets xml LPARAMETERS thFile, tnRow, tnCol, txCellValue DO CASE CASE ISNULL(txCellValue) RETURN CASE INLIST(VARTYPE(txCellValue), "C", "D", "T") .AND. EMPTY(txCellValue) RETURN CASE VARTYPE(txCellValue) = DATA_TYPE_DATE this.WriteAsInLineString(thFile, tnRow, tnCol, TRANSFORM(txCellValue)) CASE VARTYPE(txCellValue) = DATA_TYPE_DATETIME this.WriteAsInLineString(thFile, tnRow, tnCol, TTOC(txCellValue)) CASE VARTYPE(txCellValue) = DATA_TYPE_LOGICAL txCellValue = IIF(txCellValue, GETWORDNUM(this.TrueFalseValue, 1, "|"), GETWORDNUM(this.TrueFalseValue, 2, "|")) this.WriteAsInLineString(thFile, tnRow, tnCol, txCellValue) CASE VARTYPE(txCellValue) = DATA_TYPE_CURRENCY FWRITE(thFile, '') FWRITE(thFile, '' + TRANSFORM(MTON(txCellValue)) + '') CASE VARTYPE(txCellValue) = DATA_TYPE_CHAR this.WriteAsInLineString(thFile, tnRow, tnCol, ALLTRIM(txCellValue)) CASE INLIST(VARTYPE(txCellValue), DATA_TYPE_INT, DATA_TYPE_FLOAT) FWRITE(thFile, '') FWRITE(thFile, '' + TRANSFORM(txCellValue) + '') OTHERWISE FWRITE(thFile, '') FWRITE(thFile, 'Unsupported Field Type') ENDCASE ENDPROC PROTECTED PROCEDURE writedirectxmls && Writes the workbook XMLs for direct table/grid to workbook output LPARAMETERS tcPath, taSheetNames LOCAL lhFile, lcFileName, loException, lcSheetName, lnSheet, lnNumSheets EXTERNAL ARRAY taSheetNames *-* Create the supporting XML files loException = .NULL. TRY lnNumSheets = ALEN(taSheetNames, 1) CATCH TO loException ENDTRY IF !ISNULL(loException) RETURN False ENDIF TRY lhFile = FCREATE(tcPath + "[Content_Types].xml") IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FOR lnSheet=1 TO lnNumSheets FWRITE(lhFile, '') ENDFOR FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FCLOSE(lhFile) *-* Save the .rels XML lhFile = FCREATE(tcPath + "_rels\.rels") IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FCLOSE(lhFile) *-* Write the workbook relationships file lhFile = FCREATE(tcPath + "xl\_rels\workbook.xml.rels") IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FOR lnSheet=1 TO lnNumSheets FWRITE(lhFile, '') ENDFOR FWRITE(lhFile, '') FCLOSE(lhFile) *-* Save the app XML lcFileName = tcPath + "docProps\app.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, 'ExcelXMLX Release ' + TRANSFORM(this.ExcelXlsxRelease) + '') IF !EMPTY(this.CompanyName) FWRITE(lhFile, '' + this.CompanyName + '') ENDIF FWRITE(lhFile, '') FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) *-* Save the core XML lcFileName = tcPath + "docProps\core.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') IF !EMPTY(this.Title) FWRITE(lhFile, '' + this.GetXMLString(this.Title) + '') ENDIF IF !EMPTY(this.Subject) FWRITE(lhFile, '' + this.GetXMLString(this.Subject) + '') ENDIF IF !EMPTY(this.CreatorName) FWRITE(lhFile, '' + this.GetXMLString(this.CreatorName) + '') ENDIF IF !EMPTY(this.UserName) FWRITE(lhFile, '' + this.GetXMLString(this.UserName) + '') ENDIF IF VERSION(5) < 900 FWRITE(lhFile, '' + this.TTOC3(DATETIME()) + 'Z') FWRITE(lhFile, '' + this.TTOC3(DATETIME()) + 'Z') ELSE FWRITE(lhFile, '' + TTOC(DATETIME(), 3) + 'Z') FWRITE(lhFile, '' + TTOC(DATETIME(), 3) + 'Z') ENDIF FWRITE(lhFile, '') FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) *-* Save the styles XML lcFileName = tcPath + "xl\styles.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) *-* Write the workbook XML lcFileName = tcPath + "xl\workbook.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, ''+ LF) FWRITE(lhFile, '') FWRITE(lhFile, '') FOR lnSheet=1 TO lnNumSheets IF EMPTY(taSheetNames[lnSheet]) lcSheetName = "Sheet" + TRANSFORM(lnSheet) ELSE lcSheetName = taSheetNames[lnSheet] ENDIF FWRITE(lhFile, '') ENDFOR FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) CATCH TO loException SET STEP ON FCLOSE(lhFile) this.ErrorLevelId = 18 RAISEEVENT(this, "OnShowErrorMessage", 18, "Unable to create workbook supporting XMLs") ENDTRY RETURN ISNULL(loException) ENDPROC PROTECTED PROCEDURE writerelationshipsxml && Writes the relationships xml file LPARAMETERS tnWB, tcPath LOCAL lhFile, lcBaseType, llSuccess RAISEEVENT(this, "OnShowStatusMessage", 2, 5) lcBaseType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/" TRY *-* Write the workbook relationships file lhFile = FCREATE(tcPath + "xl\_rels\workbook.xml.rels") IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') SELECT xl_relationships SCAN FOR workbook = tnWB FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') llSuccess = True CATCH TO loException SET STEP ON llSuccess = False this.ErrorLevelId = 16 RAISEEVENT(this, "OnShowErrorMessage", 16, "Unable to create workbook.xml.rels") FINALLY FCLOSE(lhFile) ENDTRY RETURN llSuccess ENDPROC PROTECTED PROCEDURE writesheetxmls && Writes the Sheet XML files LPARAMETERS tnWB, tnSheetNbr, tcPath LOCAL llSuccess, lcAlias, lhFile, lcRow, lnMinCol, lnMaxCol, lnWidth, lnLastRow, lcDyDescent LOCAL lcRowDefHt, lcFileName *-* Write the sheet XML lcAlias = ALIAS() *-* Write the sheet TRY lcFileName = tcPath + "xl\worksheets\sheet" + TRANSFORM(tnSheetNbr) + ".xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF * lcDyDescent = ' x14ac:dyDescent="0.25"' && Uncomment to add back... lcDyDescent = '' lcRowDefHt = ' ht="30"' *-* Write sheet XML header information FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Write the tab color definition if set DO CASE CASE xl_sheets.tabcolorndx > 0 FWRITE(lhFile, '') CASE !EMPTY(xl_sheets.tabcolorrgb) FWRITE(lhFile, '') ENDCASE *-* Verify cells have been written SELECT xl_cells LOCATE FOR workbook = tnWB .AND. sheet = xl_sheets.sheet .AND. !celldeleted IF FOUND() *-* Write the sheet view information which includes the freeze pane information SELECT cel.sheet, MAX(cel.cellrow) AS maxrow, MAX(cel.cellcol) AS maxcol ; FROM xl_cells AS cel ; WHERE cel.workbook = tnWB ; AND cel.sheet = xl_sheets.sheet ; AND cel.celldeleted = False ; GROUP BY 1 ; INTO CURSOR t_max READWRITE FWRITE(lhFile, '') DO CASE CASE xl_sheets.ysplit > 0 .AND. xl_sheets.xsplit = 0 && Freeze top row(s) only FWRITE(lhFile, '') lcRow = TRANSFORM(xl_sheets.ysplit+1) FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_sheets.ysplit = 0 .AND. xl_sheets.xsplit > 0 && Freeze side column(s) only FWRITE(lhFile, '') lcColumn = this.ColumnIndexToAscii(xl_sheets.xsplit+1) FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_sheets.ysplit > 0 .AND. xl_sheets.xsplit > 0 && Freeze both top row(s) and side column(s) FWRITE(lhFile, '') lcRow = TRANSFORM(xl_sheets.ysplit+1) lcColumn = this.ColumnIndexToAscii(xl_sheets.xsplit+1) FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '') * FWRITE(lhFile, '') ENDCASE FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Write sheet Column widths SELECT clm.column, clm.width, clm.bestfit FROM xl_colwidths AS clm ; WHERE clm.workbook = tnWB ; AND clm.sheet = xl_sheets.sheet ; ORDER BY clm.column ; INTO CURSOR t_colwidths READWRITE IF _TALLY > 0 FWRITE(lhFile, '') SELECT t_colwidths GOTO TOP lnMinCol = t_colwidths.column lnMaxCol = t_colwidths.column lnWidth = t_colwidths.width SKIP IN t_colwidths DO WHILE !EOF('t_colwidths') DO CASE * CASE t_colwidths.bestfit && Not yet working!!! * FWRITE(lhFile, '') CASE t_colwidths.width = lnWidth .AND. t_colwidths.column-1 = lnMinCol lnMaxCol = t_colwidths.column OTHERWISE FWRITE(lhFile, '') lnMinCol = t_colwidths.column lnMaxCol = t_colwidths.column lnWidth = t_colwidths.width ENDCASE SKIP IN t_colwidths ENDDO FWRITE(lhFile, '') FWRITE(lhFile, '') ENDIF USE IN SELECT('t_colwidths') *-* Write sheet cell data values FWRITE(lhFile, '') * lnLastRow = 0 lnHeadRow = 0 SELECT xl_cells SET ORDER TO TAG cellindex SCAN FOR workbook = tnWB .AND. sheet = xl_sheets.sheet .AND. !celldeleted *-* Write row header IF lnHeadRow != xl_cells.cellrow IF lnHeadRow != 0 FWRITE(lhFile, '') ENDIF lnHeadRow = xl_cells.cellrow lnMaxCol = this.GetRowMaxColumn(tnWB, xl_sheets.sheet, lnHeadRow) IF SEEK(this.GetRowHeightKeyExpr(tnWB, xl_sheets.sheet, xl_cells.cellrow), "xl_rowheights", "shrow") FWRITE(lhFile, '') ELSE FWRITE(lhFile, '') ENDIF ENDIF *-* Write columns IF xl_cells.cellxfs > 0 lcStyle = ' s="' + TRANSFORM(xl_cells.cellxfs) + '"' ELSE lcStyle = '' ENDIF DO CASE CASE xl_cells.datatype = DATA_TYPE_TIME FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_DATE FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_DATETIME FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_LOGICAL FWRITE(lhFile, '') FWRITE(lhFile, '' + TRANSFORM(xl_cells.stringid) + '') CASE xl_cells.datatype = DATA_TYPE_CHAR FWRITE(lhFile, '') FWRITE(lhFile, '' + TRANSFORM(xl_cells.stringid) + '') CASE xl_cells.datatype = DATA_TYPE_INT FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_FLOAT FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_CURRENCY FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_PERCENT FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_FORMULA FWRITE(lhFile, '') FWRITE(lhFile, '' + ALLTRIM(xl_cells.cellformula) + '' + ALLTRIM(xl_cells.cellvalue) + '') CASE xl_cells.datatype = DATA_TYPE_NONE IF !EMPTY(lcStyle) FWRITE(lhFile, '') ENDIF ENDCASE ENDSCAN FWRITE(lhFile, '') FWRITE(lhFile, '') SET ORDER TO USE IN t_max ELSE *-* No cell data has been created/written FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') ENDIF *-* Write sheet merge data SELECT mrg.begrow, mrg.begcol, mrg.endrow, mrg.endcol FROM xl_mergecells AS mrg ; WHERE mrg.workbook = tnWB ; AND mrg.sheet = xl_sheets.sheet ; ORDER BY mrg.begrow ; INTO CURSOR t_merge IF _TALLY > 0 FWRITE(lhFile, '') SELECT t_merge SCAN FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') ENDIF USE IN t_merge *-* Write the cell validation data SELECT xl_validation COUNT FOR xl_validation.workbook = tnWB .AND. xl_validation.sheet = xl_sheets.sheet .AND. !DELETED() TO lnValidCnt IF lnValidCnt > 0 FWRITE(lhFile, '') SCAN SELECT xl.cellrow, xl.cellcol FROM xl_cells AS xl ; WHERE BINTOC(xl.workbook)+BINTOC(xl.sheet)+BINTOC(xl.validndx) = BINTOC(tnWB)+BINTOC(xl_sheets.sheet)+BINTOC(xl_validation.validndx) ; ORDER BY xl.cellrow, xl.cellcol ; INTO CURSOR t_celllist SELECT t_celllist lcSqRef = "" SCAN lcSqRef = lcSqRef + this.ColumnIndexToAscii(t_celllist.cellcol) + TRANSFORM(t_celllist.cellrow) + " " ENDSCAN lcSqRef = ALLTRIM(lcSqRef) DO CASE CASE xl_validation.vtype = NONE_VALID_TYPE lcValidationText = 'type="none"' CASE xl_validation.vtype = WHOLE_VALID_TYPE lcValidationText = 'type="whole"' CASE xl_validation.vtype = DECIMAL_VALID_TYPE lcValidationText = 'type="decimal"' CASE xl_validation.vtype = LIST_VALID_TYPE lcValidationText = 'type="list"' CASE xl_validation.vtype = DATE_VALID_TYPE lcValidationText = 'type="date"' CASE xl_validation.vtype = TIME_VALID_TYPE lcValidationText = 'type="time"' CASE xl_validation.vtype = TXTLEN_VALID_TYPE lcValidationText = 'type="textLength"' CASE xl_validation.vtype = CUSTOM_VALID_TYPE lcValidationText = 'type="custom"' OTHERWISE lcValidationText = 'type="none"' ENDCASE IF xl_validation.vstyle > 0 DO CASE CASE xl_validation.vstyle = STOP_VALID_STYLE lcValidationText = lcValidationText + ' errorStyle="stop"' CASE xl_validation.vstyle = WARN_VALID_STYLE lcValidationText = lcValidationText + ' errorStyle="warning"' CASE xl_validation.vstyle = INFO_VALID_STYLE lcValidationText = lcValidationText + ' errorStyle="information"' ENDCASE ENDIF IF xl_validation.voperator > 0 DO CASE CASE xl_validation.voperator = BETWEEN_VALID_OPER lcValidationText = lcValidationText + ' operator="between"' CASE xl_validation.voperator = NOTBETW_VALID_OPER lcValidationText = lcValidationText + ' operator="notBetween"' CASE xl_validation.voperator = EQUAL_VALID_OPER lcValidationText = lcValidationText + ' operator="equal"' CASE xl_validation.voperator = NOTEQUAL_VALID_OPER lcValidationText = lcValidationText + ' operator="notEqual"' CASE xl_validation.voperator = LESSTHAN_VALID_OPER lcValidationText = lcValidationText + ' operator="lessThan"' CASE xl_validation.voperator = LESSOREQUAL_VALID_OPER lcValidationText = lcValidationText + ' operator="lessThanOrEqual"' CASE xl_validation.voperator = GREATTHAN_VALID_OPER lcValidationText = lcValidationText + ' operator="greaterThan"' CASE xl_validation.voperator = GREATOREQUAL_VALID_OPER lcValidationText = lcValidationText + ' operator="greaterThanOrEqual"' ENDCASE ENDIF lcValidationText = lcValidationText + ' allowBlank="' + IIF(xl_validation.allowblank, '1', '0') + '"' lcValidationText = lcValidationText + ' showInputMessage="' + IIF(xl_validation.showinpmsg, '1', '0') + '"' lcValidationText = lcValidationText + ' showErrorMessage="' + IIF(xl_validation.showerrmsg, '1', '0') + '"' IF !EMPTY(xl_validation.errtitle) lcValidationText = lcValidationText + ' errorTitle="' + ALLTRIM(xl_validation.errtitle) + '"' ENDIF IF !EMPTY(xl_validation.errmsg) lcValidationText = lcValidationText + ' error="' + ALLTRIM(xl_validation.errmsg) + '"' ENDIF IF !EMPTY(xl_validation.vprompt) lcValidationText = lcValidationText + ' prompt="' + ALLTRIM(xl_validation.vprompt) + '"' ENDIF FWRITE(lhFile, '') IF xl_validation.formula FWRITE(lhFile, '' + ALLTRIM(xl_validation.formula1) + '') IF !EMPTY(xl_validation.formula2) FWRITE(lhFile, '' + ALLTRIM(xl_validation.formula2) + '') ENDIF ELSE FWRITE(lhFile, '"' + ALLTRIM(xl_validation.formula1) + '"') IF !EMPTY(xl_validation.formula2) FWRITE(lhFile, '"' + ALLTRIM(xl_validation.formula2) + '"') ENDIF ENDIF FWRITE(lhFile, '') ENDSCAN USE IN SELECT('t_celllist') FWRITE(lhFile, '') ENDIF *-* Write sheet margin data FWRITE(lhFile, '') *-* Write the sheet page print setup FWRITE(lhFile, ' 0 .AND. xl_sheets.paperheight > 0 FWRITE(lhFile, ' paperHeight="' + TRANSFORM(xl_sheets.paperheight) + xl_sheets.paperdimen + '"') FWRITE(lhFile, ' paperWidth="' + TRANSFORM(xl_sheets.paperwidth) + xl_sheets.paperdimen + '"') ELSE IF xl_sheets.papersize > 0 FWRITE(lhFile, ' paperSize="' + TRANSFORM(xl_sheets.papersize) + '"') ENDIF ENDIF DO CASE CASE xl_sheets.fittowidth > 0 .AND. xl_sheets.fittoheight > 0 FWRITE(lhFile, ' fitToWidth="' + TRANSFORM(xl_sheets.fittowidth) + '"') FWRITE(lhFile, ' fitToHeight="' + TRANSFORM(xl_sheets.fittoheight) + '"') CASE xl_sheets.fittowidth = 0 .AND. xl_sheets.fittoheight > 0 FWRITE(lhFile, ' fitToHeight="' + TRANSFORM(xl_sheets.fittoheight) + '"') CASE xl_sheets.fittowidth > 0 .AND. xl_sheets.fittoheight = 0 FWRITE(lhFile, ' fitToWidth="' + TRANSFORM(xl_sheets.fittowidth) + '"') OTHERWISE IF xl_sheets.scale != 100 FWRITE(lhFile, ' scale="' + TRANSFORM(xl_sheets.scale) + '"') ENDIF ENDCASE FWRITE(lhFile, '/>') *-* Write the header and footer for the sheet if defined IF SEEK(BINTOC(tnWB)+BINTOC(xl_sheets.sheet), "xl_hdrfooterdefn", "wbsheet") FWRITE(lhFile, '') *-* Get the page header text lcOddText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_ODD_PAGE, HEADERFOOTER_SECT_HDR_LEFT), "xl_hdrfootertext", "hdrfootr") lcOddText = IIF(EMPTY(lcOddText), '', lcOddText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_ODD_PAGE, HEADERFOOTER_SECT_HDR_CENTER), "xl_hdrfootertext", "hdrfootr") lcOddText = IIF(EMPTY(lcOddText), '', lcOddText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_ODD_PAGE, HEADERFOOTER_SECT_HDR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcOddText = IIF(EMPTY(lcOddText), '', lcOddText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcOddText) lcOddText = lcOddText + '' ENDIF lcEvenText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_EVEN_PAGE, HEADERFOOTER_SECT_HDR_LEFT), "xl_hdrfootertext", "hdrfootr") lcEvenText = IIF(EMPTY(lcEvenText), '', lcEvenText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_EVEN_PAGE, HEADERFOOTER_SECT_HDR_CENTER), "xl_hdrfootertext", "hdrfootr") lcEvenText = IIF(EMPTY(lcEvenText), '', lcEvenText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_EVEN_PAGE, HEADERFOOTER_SECT_HDR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcEvenText = IIF(EMPTY(lcEvenText), '', lcEvenText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcEvenText) lcEvenText = lcEvenText + '' ENDIF lcSameText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_HDR_LEFT), "xl_hdrfootertext", "hdrfootr") lcSameText = IIF(EMPTY(lcSameText), '', lcSameText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_HDR_CENTER), "xl_hdrfootertext", "hdrfootr") lcSameText = IIF(EMPTY(lcSameText), '', lcSameText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_HDR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcSameText = IIF(EMPTY(lcSameText), '', lcSameText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcSameText) lcSameText = lcSameText + '' ENDIF IF EMPTY(lcSameText) lcHeaderText = lcOddText + lcEvenText ELSE lcHeaderText = lcSameText ENDIF *-* Get the page footer text lcOddText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_ODD_PAGE, HEADERFOOTER_SECT_FTR_LEFT), "xl_hdrfootertext", "hdrfootr") lcOddText = IIF(EMPTY(lcOddText), '', lcOddText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_ODD_PAGE, HEADERFOOTER_SECT_FTR_CENTER), "xl_hdrfootertext", "hdrfootr") lcOddText = IIF(EMPTY(lcOddText), '', lcOddText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_ODD_PAGE, HEADERFOOTER_SECT_FTR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcOddText = IIF(EMPTY(lcOddText), '', lcOddText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcOddText) lcOddText = lcOddText + '' ENDIF lcEvenText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_EVEN_PAGE, HEADERFOOTER_SECT_FTR_LEFT), "xl_hdrfootertext", "hdrfootr") lcEvenText = IIF(EMPTY(lcEvenText), '', lcEvenText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_EVEN_PAGE, HEADERFOOTER_SECT_FTR_CENTER), "xl_hdrfootertext", "hdrfootr") lcEvenText = IIF(EMPTY(lcEvenText), '', lcEvenText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_EVEN_PAGE, HEADERFOOTER_SECT_FTR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcEvenText = IIF(EMPTY(lcEvenText), '', lcEvenText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcEvenText) lcEvenText = lcEvenText + '' ENDIF lcSameText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_FTR_LEFT), "xl_hdrfootertext", "hdrfootr") lcSameText = IIF(EMPTY(lcSameText), '', lcSameText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_FTR_CENTER), "xl_hdrfootertext", "hdrfootr") lcSameText = IIF(EMPTY(lcSameText), '', lcSameText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_SAME_PAGE, HEADERFOOTER_SECT_FTR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcSameText = IIF(EMPTY(lcSameText), '', lcSameText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcSameText) lcSameText = lcSameText + '' ENDIF IF EMPTY(lcSameText) lcFooterText = lcOddText + lcEvenText ELSE lcFooterText = lcSameText ENDIF *-* Get the first page text lcFirstHdrText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_HDR_LEFT), "xl_hdrfootertext", "hdrfootr") lcFirstHdrText = IIF(EMPTY(lcFirstHdrText), '', lcFirstHdrText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_HDR_CENTER), "xl_hdrfootertext", "hdrfootr") lcFirstHdrText = IIF(EMPTY(lcFirstHdrText), '', lcFirstHdrText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_HDR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcFirstHdrText = IIF(EMPTY(lcFirstHdrText), '', lcFirstHdrText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcFirstHdrText) lcFirstHdrText = lcFirstHdrText + '' ENDIF lcFirstFtrText = "" IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_FTR_LEFT), "xl_hdrfootertext", "hdrfootr") lcFirstFtrText = IIF(EMPTY(lcFirstFtrText), '', lcFirstFtrText) + '&L&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_FTR_CENTER), "xl_hdrfootertext", "hdrfootr") lcFirstFtrText = IIF(EMPTY(lcFirstFtrText), '', lcFirstFtrText) + '&C&' + this.GetXMLHeaderFooterText() ENDIF IF SEEK(this.GetHeaderFooterKeyExpr(tnWB, xl_sheets.sheet, HEADERFOOTER_FIRST_PAGE, HEADERFOOTER_SECT_FTR_RIGHT), "xl_hdrfootertext", "hdrfootr") lcFirstFtrText = IIF(EMPTY(lcFirstFtrText), '', lcFirstFtrText) + '&R&' + this.GetXMLHeaderFooterText() ENDIF IF !EMPTY(lcFirstFtrText) lcFirstFtrText = lcFirstFtrText + '' ENDIF *-* Write the header/footer text to XML FWRITE(lhFile, lcHeaderText + lcFooterText + lcFirstHdrText + lcFirstFtrText + '') ENDIF *-* Completed writing sheet FWRITE(lhFile, '') llSuccess = True CATCH TO loException SET STEP ON llSuccess = False this.ErrorLevelId = 14 RAISEEVENT(this, "OnShowErrorMessage", 14, loException.message) FINALLY FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) ENDTRY IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llSuccess ENDPROC PROTECTED PROCEDURE writestringsxml && Writes the sharedStrings XML LPARAMETERS tnWB, tcPath LOCAL lcFileName, lhFile, lnTotCount, lnUniqueCnt, loException, llSuccess, lnRelId RAISEEVENT(this, "OnShowStatusMessage", 2, 2) TRY SELECT xl_strformat SET ORDER TO TAG sortorder COUNT FOR workbook = tnWB .AND. !DELETED() TO lnTotCount SELECT xl_strings SET ORDER TO TAG sortorder COUNT FOR workbook = tnWB .AND. !DELETED() TO lnUniqueCnt lnTotCount = lnTotCount + lnUniqueCnt IF lnUniqueCnt > 0 *-* If the shared strings xml has not been defined in the relationships, add it IF !SEEK(BINTOC(tnWB)+"sharedStrings", "xl_relationships", "reltype") lnRelId = this.GetNextId(tnWB, "xl_relationships") INSERT INTO xl_relationships (workbook, relid, reltype, target) VALUES (tnWB, lnRelId, "sharedStrings", "sharedStrings.xml") ENDIF *-* Output the file lcFileName = tcPath + "xl\sharedStrings.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '' + LF) FWRITE(lhFile, '') && Change 19Jun2018: missplaced > SELECT xl_strings SCAN FOR workbook = tnWB .AND. !DELETED() IF xl_strings.formatted FWRITE(lhFile, '') SELECT xl_strformat SCAN FOR workbook = tnWB .AND. id = xl_strings.id .AND. !DELETED() FWRITE(lhFile, '') IF xl_strformat.fbold .OR. xl_strformat.fitalic .OR. xl_strformat.fcolor>0 .OR. !EMPTY(xl_strformat.fname) .OR. xl_strformat.fsize>0 ; .OR. xl_strformat.strkthr .OR. !EMPTY(xl_strformat.fvpos) .OR. xl_strformat.theme>0 .OR. xl_strformat.indexed>0 .OR. xl_strformat.uline != UNDERLINE_NONE FWRITE(lhFile, '') IF xl_strformat.fbold FWRITE(lhFile, '') ENDIF IF xl_strformat.fitalic FWRITE(lhFile, '') ENDIF IF xl_strformat.uline != UNDERLINE_NONE FWRITE(lhFile, '') ENDIF IF xl_strformat.strkthr FWRITE(lhFile, '') ENDIF IF xl_strformat.fsize > 0 FWRITE(lhFile, '') ENDIF DO CASE CASE xl_strformat.fcolor > 0 FWRITE(lhFile, '') CASE xl_strformat.indexed > 0 FWRITE(lhFile, '') CASE xl_strformat.theme > 0 FWRITE(lhFile, '') ENDCASE IF !EMPTY(xl_strformat.fvpos) FWRITE(lhFile, '') ENDIF IF !EMPTY(xl_strformat.fname) FWRITE(lhFile, '') ENDIF FWRITE(lhFile, '') ENDIF * IF xl_strformat.presvspace FWRITE(lhFile, '' + CHRTRAN(xl_strformat.stringxml, CHR(160), CHR(32)) + '') * ELSE * FWRITE(lhFile, '' + xl_strformat.stringxml + '') * ENDIF FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') SELECT xl_strings ELSE IF xl_strings.presvspace FWRITE(lhFile, '' + CHRTRAN(xl_strformat.stringxml, CHR(160), CHR(32)) + '') ELSE FWRITE(lhFile, '' + xl_strings.stringxml + '') ENDIF ENDIF ENDSCAN SET ORDER TO FWRITE(lhFile, '') FCLOSE(lhFile) STRTOFILE(STRCONV(FILETOSTR(lcFileName), 9), lcFileName, 4) && Save as UTF-8 ELSE *-* No strings are assigned to cells; remove from relationships if present DELETE FROM xl_relationships WHERE workbook = tnWB AND reltype = "sharedStrings" ENDIF llSuccess = True CATCH TO loException SET STEP ON llSuccess = False this.ErrorLevelId = 15 RAISEEVENT(this, "OnShowErrorMessage", 15, loException.message) ENDTRY RETURN llSuccess ENDPROC PROTECTED PROCEDURE writestylesxml && Writes the styles.xml support file LPARAMETERS tnWB, tcPath LOCAL lcAlias, lcFileName, lhFile, lnNumFmtsId, lnRecCount, lcNumFmtId, lnRotation, llIndexedColors LOCAL llMruColors RAISEEVENT(this, "OnShowStatusMessage", 2, 3) TRY lcAlias = ALIAS() lcFileName = tcPath + "xl\styles.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') *-* Get last used custom number format Id lnNumFmtsId = 0 SELECT xl_numfmts SET ORDER TO TAG sortorder SCAN FOR workbook = tnWB .AND. xl_numfmts.id < 900 IF xl_numfmts.id > lnNumFmtsId lnNumFmtsId = xl_numfmts.id ENDIF ENDSCAN *-* Write the Number format section COUNT FOR workbook = tnWB TO lnRecCount FWRITE(lhFile, '') SCAN FOR workbook = tnWB IF xl_numfmts.id > 900 lnNumFmtsId = lnNumFmtsId + 1 FWRITE(lhFile, '') REPLACE xl_numfmts.tempid WITH lnNumFmtsId IN xl_numfmts ELSE FWRITE(lhFile, '') REPLACE xl_numfmts.tempid WITH xl_numfmts.id IN xl_numfmts ENDIF ENDSCAN FWRITE(lhFile, '') SET ORDER TO *-* Write the fonts section SELECT xl_fonts SET ORDER TO TAG sortorder COUNT FOR workbook = tnWB TO lnRecCount FWRITE(lhFile, '') SCAN FOR workbook = tnWB FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') IF xl_fonts.fbold FWRITE(lhFile, '') ENDIF IF xl_fonts.fitalic FWRITE(lhFile, '') ENDIF IF !EMPTY(xl_fonts.uline) FWRITE(lhFile, '') ENDIF IF xl_fonts.strkthr FWRITE(lhFile, '') ENDIF IF !EMPTY(xl_fonts.fvpos) FWRITE(lhFile, '') ENDIF DO CASE CASE xl_fonts.fcolor > 0 FWRITE(lhFile, '') CASE xl_fonts.indexed > 0 FWRITE(lhFile, '') CASE xl_fonts.theme > 0 FWRITE(lhFile, '') ENDCASE FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') SET ORDER TO *-* Write the fills section SELECT xl_fills SET ORDER TO TAG sortorder COUNT FOR workbook = tnWB TO lnRecCount FWRITE(lhFile, '') SCAN FOR workbook = tnWB FWRITE(lhFile, ' 0 .AND. xl_fills.bgindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_fills.fgcolor > 0 .AND. xl_fills.bgindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_fills.bgcolor > 0 .AND. xl_fills.fgindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_fills.fgcolor > 0 .AND. xl_fills.bgcolor > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_fills.theme > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '/>') ENDCASE FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') *-* Write the borders section SELECT xl_borders SET ORDER TO TAG sortorder COUNT FOR workbook = tnWB TO lnRecCount FWRITE(lhFile, '') SCAN FOR workbook = tnWB FWRITE(lhFile, '') IF EMPTY(xl_borders.lstyle) FWRITE(lhFile, '') ELSE IF xl_borders.lstyle = BORDER_STYLE_NONE FWRITE(lhFile, ' 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.lindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.ltheme > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '/>') ENDCASE ENDIF IF EMPTY(xl_borders.rstyle) FWRITE(lhFile, '') ELSE IF xl_borders.rstyle = BORDER_STYLE_NONE FWRITE(lhFile, ' 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.rindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.rtheme > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '/>') ENDCASE ENDIF IF EMPTY(xl_borders.tstyle) FWRITE(lhFile, '') ELSE IF xl_borders.tstyle = BORDER_STYLE_NONE FWRITE(lhFile, ' 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.tindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.ttheme > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '/>') ENDCASE ENDIF IF EMPTY(xl_borders.bstyle) FWRITE(lhFile, '') ELSE IF xl_borders.bstyle = BORDER_STYLE_NONE FWRITE(lhFile, ' 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.bindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.btheme > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '/>') ENDCASE ENDIF IF EMPTY(xl_borders.dstyle) FWRITE(lhFile, '') ELSE IF xl_borders.dstyle = BORDER_STYLE_NONE FWRITE(lhFile, ' 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.dindexed > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') CASE xl_borders.dtheme > 0 FWRITE(lhFile, '>') FWRITE(lhFile, '') FWRITE(lhFile, '') OTHERWISE FWRITE(lhFile, '/>') ENDCASE ENDIF FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') *-* Write the cellStyleXfs section *-* Write the cellXfs section SELECT xl_cellxfs SET ORDER TO TAG sortorder COUNT FOR workbook = tnWB TO lnRecCount FWRITE(lhFile, '') SCAN FOR workbook = tnWB IF xl_cellxfs.numFmtId > 0 .AND. SEEK(BINTOC(tnWB)+BINTOC(xl_cellxfs.numFmtId), "xl_numfmts", "id") lcNumFmtId = TRANSFORM(xl_numfmts.tempid) ELSE lcNumFmtId = TRANSFORM(xl_cellxfs.numFmtId) ENDIF FWRITE(lhFile, ' 0, ' applyFont="1"', '') + ; IIF(xl_cellxfs.fillid > 0, ' applyFill="1"', '') + IIF(xl_cellxfs.borderid > 0, ' applyBorder="1"', '') + ' applyAlignment="1"') IF !EMPTY(xl_cellxfs.halign) .OR. !EMPTY(xl_cellxfs.valign) .OR. xl_cellxfs.wraptext > 0 .OR. xl_cellxfs.indent > 0 .OR. xl_cellxfs.rotation > 0 FWRITE(lhFile, '> 0 FWRITE(lhFile, ' wrapText="1"') ENDIF IF xl_cellxfs.indent > 0 FWRITE(lhFile, ' indent="' + TRANSFORM(xl_cellxfs.indent) + '"') ENDIF IF xl_cellxfs.rotation != 0 FWRITE(lhFile, ' textRotation="' + TRANSFORM(xl_cellxfs.rotation) + '"') ENDIF FWRITE(lhFile, '/>') ELSE FWRITE(lhFile, '/>') ENDIF ENDSCAN FWRITE(lhFile, '') *-* Write the colors section llIndexedColors = SEEK(BINTOC(tnWB)+BINTOC(1), "xl_ndxcolors", "indexid") llMruColors = SEEK(BINTOC(tnWB)+BINTOC(1), "xl_mrucolors", "indexid") IF llIndexedColors .OR. llMruColors FWRITE(lhFile, '') IF llIndexedColors FWRITE(lhFile, '') SELECT xl_ndxcolors SET ORDER TO TAG indexid SCAN FOR workbook = tnWB FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') ENDIF IF llMruColors FWRITE(lhFile, '') SELECT xl_mrucolors SET ORDER TO TAG indexid SCAN FOR workbook = tnWB FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') ENDIF FWRITE(lhFile, '') ENDIF *-* Close the style sheet FWRITE(lhFile, '') llSuccess = True CATCH TO loException SET STEP ON llSuccess = False this.ErrorLevelId = 17 RAISEEVENT(this, "OnShowErrorMessage", 17, "Unable to create styles.xml") FINALLY FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) ENDTRY IF !EMPTY(lcAlias) SELECT &lcAlias ENDIF RETURN llSuccess ENDPROC PROTECTED PROCEDURE writesupportxmls && Writes the [Content_Types].xml, .rels, core.xml, workbook.xml.rels and app.xml files LPARAMETERS tnWB, tcPath LOCAL llSuccess, loException, lhFile, lnSheet, lnUniqueCnt, lcCurr, lcColor, lnTotCount, lcFileName, lcBaseContentType RAISEEVENT(this, "OnShowStatusMessage", 2, 1) TRY lhFile = FCREATE(tcPath + "[Content_Types].xml") IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') lcBaseContentType = '') CASE xl_relationships.reltype = "drawings" * FWRITE(lhFile, lcBaseContentType + 'drawing+xml" PartName="/xl/drawings/drawing1.xml"/>') CASE xl_relationships.reltype = "externalLink" * FWRITE(lhFile, lcBaseContentType + 'externalLink+xml" PartName="/xl/externalLinks/externalLink1.xml"/>') CASE xl_relationships.reltype = "sharedStrings" FWRITE(lhFile, lcBaseContentType + 'sharedStrings+xml" PartName="/xl/sharedStrings.xml"/>') CASE xl_relationships.reltype = "styles" FWRITE(lhFile, lcBaseContentType + 'styles+xml" PartName="/xl/styles.xml"/>') CASE xl_relationships.reltype = "theme" * FWRITE(lhFile, lcBaseContentType + 'theme+xml" PartName="/xl/theme/theme1.xml"/>') CASE xl_relationships.reltype = "worksheet" FWRITE(lhFile, lcBaseContentType + 'worksheet+xml" PartName="/xl/worksheets/sheet' + TRANSFORM(xl_relationships.sheet) + '.xml"/>') ENDCASE ENDSCAN FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FCLOSE(lhFile) *-* Save the .rels XML lhFile = FCREATE(tcPath + "_rels\.rels") IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, '') FCLOSE(lhFile) *-* Save the app XML lcFileName = tcPath + "docProps\app.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') FWRITE(lhFile, 'ExcelXMLX Release ' + TRANSFORM(this.ExcelXlsxRelease) + '') IF !EMPTY(this.CompanyName) FWRITE(lhFile, '' + this.CompanyName + '') ENDIF FWRITE(lhFile, '') FCLOSE(lhFile) STRTOFILE(STRCONV(FILETOSTR(lcFileName), 9), lcFileName, 4) && Save as UTF-8 *-* Save the core XML lcFileName = tcPath + "docProps\core.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, '') FWRITE(lhFile, '') IF !EMPTY(this.Title) FWRITE(lhFile, '' + this.GetXMLString(this.Title) + '') ENDIF IF !EMPTY(this.Subject) FWRITE(lhFile, '' + this.GetXMLString(this.Subject) + '') ENDIF IF !EMPTY(this.CreatorName) FWRITE(lhFile, '' + this.GetXMLString(this.CreatorName) + '') ENDIF IF !EMPTY(this.UserName) FWRITE(lhFile, '' + this.GetXMLString(this.UserName) + '') ENDIF IF VERSION(5) < 900 FWRITE(lhFile, '' + this.TTOC3(DATETIME()) + 'Z') FWRITE(lhFile, '' + this.TTOC3(DATETIME()) + 'Z') ELSE FWRITE(lhFile, '' + TTOC(DATETIME(), 3) + 'Z') FWRITE(lhFile, '' + TTOC(DATETIME(), 3) + 'Z') ENDIF FWRITE(lhFile, '') FCLOSE(lhFile) STRTOFILE(STRCONV(FILETOSTR(lcFileName), 9), lcFileName, 4) && Save as UTF-8 llSuccess = True CATCH TO loException SET STEP ON llSuccess = False this.ErrorLevelId = 18 RAISEEVENT(this, "OnShowErrorMessage", 18, "Unable to create workbook supporting XMLs") ENDTRY RETURN llSuccess ENDPROC PROTECTED PROCEDURE writeworkbookxml && Writes the workbook XML LPARAMETERS tnWB, tcPath LOCAL lcFileName, lhFile, loException, llSuccess, lcSheetName RAISEEVENT(this, "OnShowStatusMessage", 2, 4) TRY lcFileName = tcPath + "xl\workbook.xml" lhFile = FCREATE(lcFileName) IF lhFile < 0 THROW ENDIF FWRITE(lhFile, ''+ LF) FWRITE(lhFile, '') *-* Write thw sheet information FWRITE(lhFile, '') SELECT xl_relationships SET ORDER TO TAG relid SCAN FOR workbook = tnWB .AND. reltype = "worksheet" IF SEEK(BINTOC(tnWB)+BINTOC(xl_relationships.sheet), "xl_sheets", "sheetndx") DO CASE CASE xl_sheets.state = VISIBLE_SHEET_STATE FWRITE(lhFile, '') CASE xl_sheets.state = HIDDEN_SHEET_STATE FWRITE(lhFile, '') CASE xl_sheets.state = VERYHIDDEN_SHEET_STATE FWRITE(lhFile, '') ENDCASE ELSE THROW ENDIF ENDSCAN SET ORDER TO FWRITE(lhFile, '') *-* Write the named range information SELECT xl_namerange LOCATE FOR workbook = tnWB .AND. !DELETED() IF FOUND() FWRITE(lhFile, '') SCAN FOR workbook = tnWB .AND. !DELETED() IF (xl_namerange.begcol = 0 .AND. xl_namerange.begrow = 0) .OR. (xl_namerange.begcol = 0 .AND. xl_namerange.begrow = 0) LOOP ENDIF FWRITE(lhFile, '') lcSheetName = this.GetSheetName(tnWB, xl_namerange.sheet) FWRITE(lhFile, IIF(OCCURS(" ", lcSheetName)>0, "'", "") + lcSheetName + IIF(OCCURS(" ", lcSheetName)>0, "'", "")) DO CASE CASE xl_namerange.begcol = 0 .AND. xl_namerange.begrow > 0 FWRITE(lhFile, '!$' + TRANSFORM(xl_namerange.begrow)) CASE xl_namerange.begcol > 0 .AND. xl_namerange.begrow = 0 FWRITE(lhFile, '!$' + this.ColumnIndexToAscii(xl_namerange.begcol)) OTHERWISE FWRITE(lhFile, '!$' + this.ColumnIndexToAscii(xl_namerange.begcol) + '$' + TRANSFORM(xl_namerange.begrow)) ENDCASE DO CASE CASE xl_namerange.endcol = 0 .AND. xl_namerange.endrow > 0 FWRITE(lhFile, ':$' + TRANSFORM(xl_namerange.endrow)) CASE xl_namerange.endcol > 0 .AND. xl_namerange.begrow = 0 FWRITE(lhFile, ':$' + this.ColumnIndexToAscii(xl_namerange.endcol)) OTHERWISE FWRITE(lhFile, ':$' + this.ColumnIndexToAscii(xl_namerange.endcol) + '$' + TRANSFORM(xl_namerange.endrow)) ENDCASE FWRITE(lhFile, '') ENDSCAN FWRITE(lhFile, '') ENDIF *-* Close the workbook FWRITE(lhFile, '') FWRITE(lhFile, '') llSuccess = True CATCH TO loException FCLOSE(lhFile) SET STEP ON llSuccess = False FINALLY FCLOSE(lhFile) this.SaveAsUTF8(lcFileName) ENDTRY RETURN llSuccess ENDPROC ENDDEFINE