home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual dBase Pro v7.0 / DATA1.CAB / Utilities / Upgrade / RptToRepConv.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-20  |  109.4 KB  |  2,931 lines

  1. /******************************************************************************
  2. * Filename:      RptToRepConv.CC                                              *
  3. * Last Modified: 11/18/97                                                     *
  4. * Author:        Jim Sare                                                     *
  5. *                                                                             *
  6. * Created under agreement with KSoft, Inc. for Borland International, Inc.    *
  7. *                                                                             *
  8. * Copyright (c) 1997 Borland International, Inc.  All Rights Reserved.        *
  9. *                                                                             *
  10. ******************************************************************************/
  11. *
  12. /******************************************************************************
  13. * Assumptions: - CRW .RPT will be mapped to a single VdB PageTemplate.        *
  14. *              - CRW Band Line text will be streamed to VdB .REP file as HTML.*
  15. *              - CRW Field objects will be streamed to VdB .REP file as VdB   *
  16. *                Text class instances.                                        *
  17. *              - CRW Line objects will be streamed to VdB .REP file as VdB    *
  18. *                Line class instances.                                        *
  19. *              - CRW Image objects will be streamed to VdB .REP file as VdB   *
  20. *                Image class instances.                                       *
  21. *              - CRW OLE objects will not be translated, but will be flagged  *
  22. *                as exceptions in the error log streamed to the VdB .REP      *
  23. *                header.                                                      *
  24. *              - CRW .RPT comments (CRW menu Format|Report Title...) will be  *
  25. *                streamed as comments in the VdB .REP header.                 *
  26. *              - CRW .RPT title (CRW menu Format|Report Title...) will be     *
  27. *                streamed to VdB .REP file.                                   *
  28. *              - Labels (standard and user-defined) and other multi-column    *
  29. *                reports are supported.                                       *
  30. * Note: In most cases, it may be necessary to manually touch-up the resulting *
  31. *       .REP file. A 100% conversion is not possible due to differences       *
  32. *       between .RPT and .REP capabilities, and ability to map .RPT elements  *
  33. *       to .REP elements during the conversion process.                       *
  34. ******************************************************************************/
  35. //
  36. // See RptToRepConv.H for associated Win32 API constants
  37. // and other constants and preprocessor macros used in this file.
  38. // All preprocessor labels used in this file are in upper case.
  39. //
  40. #include RptToRepConv.H
  41. //
  42. CLASS ReportConverter(oForm)
  43.  
  44.     // Prototype necessary Win32 API functions.
  45.     If Type("BL_CreateFont") # "FP"
  46.         extern CHANDLE BL_CreateFont(CINT, CINT, CINT, CINT, CINT,;
  47.                                             CLOGICAL, CLOGICAL, CLOGICAL,;
  48.                                             CINT, CINT, CINT, CINT, CINT, CPTR) GDI32;
  49.                     From "CreateFontA"
  50.     EndIf
  51.     If Type("BL_DeleteObject") # "FP"
  52.         extern CLOGICAL BL_DeleteObject(CHANDLE) GDI32;
  53.                     From "DeleteObject"
  54.     EndIf
  55.     If Type("BL_GetDC") # "FP"
  56.         extern CLONG BL_GetDC(CLONG) User32;
  57.                     From "GetDC"
  58.     EndIf
  59.     If Type("BL_GetDeviceCaps") # "FP"
  60.         extern CINT BL_GetDeviceCaps(CHANDLE, CINT) GDI32;
  61.                     From "GetDeviceCaps"
  62.     EndIf
  63.     If Type("BL_GetTextExtentPoint32") # "FP"
  64.         extern CLOGICAL BL_GetTextExtentPoint32(CHANDLE, CSTRING, CLONG, CPTR) gdi32;
  65.                     From "GetTextExtentPoint32A"
  66.     EndIf
  67.     If Type("BL_lReleaseDC") # "FP"
  68.         extern CLOGICAL BL_lReleaseDC(CHANDLE, CHANDLE) User32;
  69.                     From "ReleaseDC"
  70.     EndIf
  71.     If Type("BL_SelectObject") # "FP"
  72.         extern CHANDLE BL_SelectObject(CHANDLE, CHANDLE) GDI32;
  73.                     From "SelectObject"
  74.     EndIf
  75.     If Type("BL_SetMapMode") # "FP"
  76.         extern CINT BL_SetMapMode(CHANDLE, CINT) GDI32;
  77.                     From "SetMapMode"
  78.     EndIf
  79.     If Type("BL_UpdateWindow") # "FP"
  80.         extern CLOGICAL BL_UpdateWindow(CHANDLE) User32;
  81.                     From "UpdateWindow"
  82.     EndIf
  83.  
  84.     this.CriticalError =        False                    // Internal flag for critical erors
  85.     this.oForm =                oForm                    // Reference to wizard form
  86.     this.aQBEFiles =            oForm.oQuery        // Reference to query parser array
  87.     this.lRelatedTables =    False                    // Flag for related tables
  88.     this.ProgressObject =    Null                    // oRef to Progress object on form
  89.     this.ShowProgress =        False                    // Flag to not show/show progress
  90.     this.aErrors =                New Array()            // Conversion exception log
  91.     this.oError =                New RBException(oForm)    // Exception status object
  92.     this.InFilename =            ""                        // Input .RPT/.RPL filename
  93.     this.hInFile =                0                        // Handle to input .RPT file
  94.     this.nFSize =                0                        // Input .RPT/.RPL file size
  95.     this.nFPos =                0                        // Input .RPT/.RPL file pointer
  96.     this.RecID =                0                        // Input record type
  97.     this.RecTypeDescr =        "Unknown Record"    // Input record description
  98.     this.RecLen =                0                        // Input record length (variable)
  99.     this.xREC =                    ""                        // Input record data
  100.     this.xSIZE =                SPACE(4)                // Buffer Win32 API SIZE structure
  101.     this.OutFilename =        ""                        // Output .REP filename
  102.     this.hOutFile =            0                        // Handle to output .REP file
  103.     this.hDC =                    0                        // Handle to printer DC
  104.     this.ItemWidth =            0                        // Width of text item
  105.     this.ItemHeight =            0                        // Height of text item
  106.     this.oReport =                Null                    // Main report array
  107.     this.oPrinter =            Null                    // Report Printer object
  108.     this.oPageTemplate =        Null                    // Report PageTemplate object
  109.     this.ObjectCount =        0                        // Count of objects in report + 1
  110.     this.StreamCount =        0                        // Count of objects streamed
  111.     this.TextCount =            0                        // Count of bandline text characters
  112.     this.SaveVarHeight =        0                        // Buffer for variable height indicator
  113.  
  114.     this.StreamAll =            False                    // Diagnostic only!!!
  115.     this.Debug =                False                    // Diagnostic only!!!
  116.  
  117.     this.oDetailBand =        Null                    // Reference to detail band object
  118.     this.CurrentBand =        Null                    // Reference to current band object
  119.     this.CurrentLine =        Null                    // Reference to current line object
  120.     this.CurrentObject =        Null                    // Reference to current object being built
  121.     this.cStreamQuery =        ""                        // Name of Query containing StreamSource.RowSet
  122.     this.aGroups =                New Array()            // Array of report groups
  123.     this.CurrentTable =        ""                        // Temp buffer for table name
  124.     this.OrderBy =                ""                        // Order By field
  125.     this.OrderByTable =        ""                        // Order By table
  126.     this.SortOrder =            "ASC"                    // Default sort order
  127.     this.GroupBy =                ""                        // Group By field
  128.     this.GroupByTable =        ""                        // Group By table
  129.  
  130.     this.aCRWBands =            New Array()            // Array of CRW Band objects
  131.     this.aLines =                New Array()            // Array of VdB Line objects
  132.     this.aShapes =                New Array()            // Array of VdB Shape objects
  133.     this.aQueries =            New Array()            // Array of VdB Query objects
  134.  
  135.     this.BandID =                0                        // Band type identifier
  136.     this.ReadingLine =        False                    // Flag for reading CRWLine data
  137.     this.RawHText =            ""                        // Band Line text accumulator
  138.     this.aaColors =            New RGBTripleColors()    // Color conversion array
  139.     this.CurColor =            HTML_DEFCOLOR        // Current font color
  140.     this.NewColor =            0                        // New font color
  141.     this.CurFName =            HTML_DEFFACE        // Current FontName
  142.     this.NewFName =            ""                        // New FontName
  143.     this.CurFSize =            HTML_DEFFNSZ        // Current FontSize
  144.     this.NewFSize =            0                        // New FontSize
  145.     this.CurFSizeTag =        "0"                    // Current FontSize tag
  146.     this.CurFBold =            HTML_DEFBOLD        // Current FontBold
  147.     this.NewFBold =            0                        // New FontBold
  148.     this.CurFItal =            HTML_DEFITAL        // Current FontItalic
  149.     this.NewFItal =            False                    // New FontItalic
  150.     this.CurFUnln =            HTML_DEFUNLN        // Current FontUnderline
  151.     this.NewFUnln =            False                    // New FontUnderline
  152.  
  153.     this.PreDefLabel =        False                    // Flag pre-defined label type
  154.     this.MultiColumn =        False                    // Flag multi-columns (labels and user-defined)
  155.     this.ColWidth =            0                        // Column width
  156.     this.ColHeight =            0                        // Column height
  157.     this.ColGapHorz =            0                        // Horizontal gap between columns
  158.     this.ColGapVert =            0                        // Vertical gap between entries
  159.     this.ColSequence =        0                        // Rendering sequence (Across/Down)
  160.  
  161.     this.ReadingRptHeader =    False                    // Flag for reading rpt header band
  162.     this.ReadingGrpHeader =    False                    // Flag for reading grp header band
  163.     this.ReadingRptDetail =    False                    // Flag for reading rpt detail band
  164.     this.ReadingGrpFooter =    False                    // Flag for reading grp footer band
  165.     this.ReadingGrandTotal = False                // Flag for reading grand total band
  166.     this.ReadingRptFooter =    False                    // Flag for reading rpt footer band
  167.     this.ReadingGrpInfo =    False                    // Flag for reading grp field
  168.  
  169.     this.lLogColorError =    True                    // Prevent multiple color error logs
  170.  
  171.     this.FenceVersion =        True                    // Fence .RPT/.RPL version range
  172.     this.FenceLo =                3.0                    // Low .RPT/.RPL version
  173.     this.FenceHi =                3.1                    // High .RPT/.RPL version
  174.  
  175.     // Protect unpublished custom property members
  176.     PROTECT aaColors, aCRWBands, aGroups, aLines, aQBEFiles, aQueries, aShapes,;
  177.                 BandID, ColGapHorz, ColGapVert, ColHeight, ColSequence, ColWidth,;
  178.                 CriticalError, CurColor, CurFBold, CurFItal, CurFName, CurFSize,;
  179.                 CurFSizeTag, CurFUnLn, CurrentBand, CurrentLine, CurrentObject,;
  180.                 CurrentTable, Debug, FenceHi, FenceLo, FenceVersion
  181.     PROTECT GroupBy, GroupByTable, HDC, hInFile, hOutFile, ItemHeight,;
  182.                 ItemWidth, lLogColorError, lRelatedTables, Multicolumn, NewColor,;
  183.                 NewFBold, NewFItal, NewFName, NewFSize, NewFUnLn, nFPos, nFSize,;
  184.                 ObjectCount, oDetailBand, oError, oForm, oGroup, oPageTemplate,;
  185.                 oPrinter, OrderBy, OrderByTable, oReport, PreDefLabel
  186.     PROTECT RawHText, ReadingGrandTotal, ReadingGrpFooter, ReadingGrpHeader,;
  187.                 ReadingGrpInfo, ReadingLine, ReadingRptDetail, ReadingRptFooter,;
  188.                 ReadingRptHeader, RecID, RecLen, RecTypeDescr, SaveVarHeight,;
  189.                 SortOrder, StreamAll, StreamCount, xREC, xSIZE
  190.  
  191.     // Protect unpublished custom method members
  192.     PROTECT AddToReport, ConvertFormula, ConvertField, GetItemSize, ReadRecord,;
  193.                 SkipNulls, StreamComments, StreamBannerLine, ArrangeZOrder;
  194.                 StreamHeader, StreamObject, UpdateProgress, FieldType
  195.  
  196.     FUNCTION BuildReport
  197.         // Check .RPT file format and build in-memory image of report.
  198.         // Returns:    True if good .RPT file format and no fatal errors detected,
  199.         //                False if bad format or fatal error detected.
  200.         LOCAL xRECHDR, aBands, aLines, cTemp, lTemp, nTemp, oTemp, nPQuality
  201.         LOCAL nBandTop, DownCount, nTop, nLeft, nHorz, nVert
  202.  
  203.         BL_UpdateWindow(this.oForm.hWND)
  204.         this.oError.ClearError()                    // Initialize error object
  205.         Try
  206.             this.hInFile = fOpen((this.InFilename), "R")
  207.         Catch(Exception x)    // Catch any error generated by fOpen and cancel run
  208.             this.oError.OnError(x)
  209.             RETURN False
  210.         EndTry
  211.         // Now the entire .RPT file is read. Errors are caught by the Catch clauses
  212.         // at the end of this function, a message is displayed describing the error,
  213.         // and the conversion run is cancelled.
  214.         // Program-detected errors are Thrown to the RBException Catch clause.
  215.         // VdB-detected hard errors are caught by the Exception Catch clause.
  216.         //
  217.         // Any modifications to this code should preserve this scheme to ensure
  218.         // that the device context handle used during the conversion process is
  219.         // released to avoid GDI loss, and to ensure that the file handle to the
  220.         // .RPT file is closed.
  221.         Try
  222.             this.nFSize = FSize(this.InFilename)
  223.             this.oError.Filename = Program()
  224.             // Verify correct .RPT file format
  225.             xRECHDR = fRead(this.hInFile, 4)
  226.             // First 2 bytes should be 0x1000 (LSB/MSB order)
  227.             this.oError.Code = 10014
  228.             If MAKEU32(xRECHDR, 1) = HToI("E011CFD0")    // Report contains OLE item
  229.                 this.oError.LineNo = LineNo() - 1
  230.                 Throw this.oError
  231.             EndIf
  232.             this.oError.Code = 10001
  233.             If MAKEU16(xRECHDR, 1) # HToI("1000")    // Invalid record type
  234.                 this.oError.LineNo = LineNo() - 1
  235.                 Throw this.oError
  236.             EndIf
  237.             this.RecLen = MAKEU16(xRECHDR, 3)
  238.             If this.RecLen < 4                        // Invalid record length
  239.                 this.oError.LineNo = LineNo() - 1
  240.                 Throw this.oError
  241.             EndIf
  242.             // Now read entire file and verify record length integrity
  243.             fSeek(this.hInFile, 0)                    // Rewind input file to beginning
  244.             this.nFPos = 0
  245.             this.ObjectCount = 0
  246.             // Update Wizard form progress display
  247.             this.UpdateProgress((this.nFPos / this.nFSize) * 100)
  248.             cTemp = this.OutFilename
  249.             If RAt("\", cTemp) > 0
  250.                 cTemp = Right(cTemp, Len(cTemp) - RAt("\", cTemp))
  251.             EndIf
  252.             If RAt(".", cTemp) > 0
  253.                 cTemp = Left(cTemp, RAt(".", cTemp) - 1)
  254.             EndIf
  255.             // Obtain device context used during conversion to determine
  256.             // item display sizes.
  257.             this.hDC = BL_GetDC(_app.FrameWin.hWND)
  258.             // The .RPT file specifies coordinates in twips.
  259.             // We will write the .REP file specifying twips also.
  260.             // So we need to map the device context to twips.
  261.             BL_SetMapMode(this.hDC, MM_TWIPS)
  262.             // The xReport template object is the main .REP array cluster into
  263.             // which all other template objects are stored. Some of these template
  264.             // objects are also containers for other template objects.
  265.             this.oReport = New xReport(cTemp)
  266.             // Instantiate basic template objects used in all .REP files. They will
  267.             // be added to the oReport .REP array cluster later.
  268.             this.oPrinter = New xPrinter()
  269.             this.oStreamSource =;
  270.                             New xStreamSource(this.oReport.NextName("STREAMSOURCE"))
  271.             this.oPageTemplate =;
  272.                             New xPageTemplate(this.oReport.NextName("PAGETEMPLATE"))
  273.             this.oStreamFrame =;
  274.                             New xStreamFrame(this.oPageTemplate.NextName("STREAMFRAME"))
  275.             this.oGroup = Null
  276.             this.CurrentContainer = this.oReport
  277.             this.CurrentBand = Null
  278.             this.CurrentLine = Null
  279.             this.CurrentObject = Null
  280.             // Read entire .RPT file in DO...ENDDO loop.
  281.             // The .RPT file contains variable-length records of the format:
  282.             // XXXX - 2 bytes describing the record type (RecID)
  283.             // YYYY - 2 bytes containing the record length (RecLen)
  284.             // Z..Z - (RecLen) bytes of data.
  285.             // Note that not all data in all records is used during the
  286.             // conversion process. We only attempt to extract those data
  287.             // elements that are critical to basic VdB report operation.
  288.             Do While Not fEOF(this.hInFile)
  289.                 xRECHDR = fRead(this.hInFile, 4)
  290.                 this.nFPos += 4
  291.                 this.RecID = MAKEU16(xRECHDR, 1)
  292.                 this.RecLen = MAKEU16(xRECHDR, 3)
  293.                 Do Case
  294.                     Case this.RecID = 0             // Garbage Area
  295.                         this.SkipNulls()
  296.  
  297.                     Case this.RecID = HToI("1000")  // Report Descriptor
  298.                         this.RecTypeDescr = "Report Descriptor"
  299.                         this.ReadRecord()
  300.                         this.ReportDescriptor = this.xREC
  301.                         this.VersionRPT = CHARNUM(MAKEU16(this.xREC, 1)) +;
  302.                                                 "." +;
  303.                                                 CHARNUM(MAKEU16(this.xREC, 3))
  304.                         If this.FenceVersion And;
  305.                                     (Val(this.VersionRPT) < this.FenceLo Or;
  306.                                      Val(this.VersionRPT) > this.FenceHi)
  307.                             this.oError.LineNo = LineNo() - 1
  308.                             this.oError.Filename = Program()
  309.                             this.oError.Code = 10002
  310.                             Throw this.oError
  311.                         EndIf
  312.  
  313.                     // Do NOT remove the following 2 lines!
  314.                     // Record Type 1001 has subrecords inside it.
  315.                     Case this.RecID = HToI("1001")  // Data View Descriptor Block
  316.                         this.RecTypeDescr = "Data View Cluster"
  317.  
  318.                     Case this.RecID = HToI("1002")  // Band Descriptor (New band)
  319.                         // This case is encountered once for each report band.
  320.                         // The first time it occurs, all data table information in
  321.                         // RecID's 2xxx have previously been read. The first band to
  322.                         // occur in the .RPT file is the header band. So when the
  323.                         // header band is encountered (ReadingRptHeader), the data
  324.                         // table information from the .RPT can be synced with the
  325.                         // information from the .QBE file specified in the .RPT file
  326.                         // if any .QBE file was specified.
  327.                         this.RecTypeDescr = "Band Descriptor"
  328.                         // Add any previously extracted objects to .REP stream.
  329.                         this.AddToReport()
  330.                         this.ReadRecord()
  331.                         this.CurrentLine = Null
  332.                         this.ReadingLine = False
  333.                         // Add a new band container
  334.                         this.aCRWBands.Add(New CRWBand(this.xREC))
  335.                         this.BandID = MAKEU16(this.xREC, 3)
  336.                         this.ReadingRptHeader = this.BandID = CRWBAND_RPTHEADER
  337.                         // If the current band being read is the report header band
  338.                         If this.ReadingRptHeader
  339.                             // Verify formula count is correct. If not, corrupt file.
  340.                             If this.oReport.FormulaCount #;
  341.                                                             this.oReport.aaFormulas.Count()
  342.                                 this.oError.LineNo = LineNo() - 1
  343.                                 this.oError.Filename = Program()
  344.                                 this.oError.Code = 10011
  345.                                 Throw this.oError
  346.                             EndIf
  347.                             // Query objects are contained in the report class.
  348.                             this.CurrentContainer = this.oReport
  349.                             // Reading of data table information is now complete.
  350.                             // Now merge the data information from the report
  351.                             // with the information from the query (if any).
  352.                             //
  353.                             // If the report is based on a .QBE file
  354.                             If this.oReport.aTables.Size = this.aQBEFiles.Size / 8
  355.                                 For nTemp = 1 To this.oReport.aTables.Size
  356.                                     lTemp = (this.oReport.aTables.Size + 1) - nTemp
  357.                                     this.oReport.aTables[lTemp].Alias =;
  358.                                                                 this.aQBEFiles[nTemp, QALIAS]
  359.                                 EndFor
  360.                             EndIf
  361.                             If this.aQBEFiles.Size > 6
  362.                                 For nTemp = 1 To this.aQBEFiles.Size / 8
  363.                                     For lTemp = 1 To this.oReport.aTables.Size
  364.                                         If this.oReport.aTables[lTemp].Alias ==;
  365.                                                             this.aQBEFiles[nTemp, QALIAS]
  366.                                             this.oReport.aTables[lTemp].TableName =;
  367.                                                             this.aQBEFiles[nTemp, QTABLENAME]
  368.                                             this.oReport.aTables[lTemp].Alias =;
  369.                                                             this.aQBEFiles[nTemp, QALIAS]
  370.                                             this.oReport.aTables[lTemp].ParentTable =;
  371.                                                             this.aQBEFiles[nTemp, QPARENTTABLE]
  372.                                             this.oReport.aTables[lTemp].ParentField =;
  373.                                                             this.aQBEFiles[nTemp, QPARENTFIELD]
  374.                                             this.oReport.aTables[lTemp].Order =;
  375.                                                             this.aQBEFiles[nTemp, QORDER]
  376.                                             this.oReport.aTables[lTemp].Error =;
  377.                                                             this.aQBEFiles[nTemp, QERROR]
  378.                                             this.oReport.aTables[lTemp].Tag =;
  379.                                                             this.aQBEFiles[nTemp, QTAG]
  380.                                         EndIf
  381.                                     EndFor
  382.                                 EndFor
  383.                             EndIf
  384.                             // If the report is based on a single table (ie; .QBE not used)
  385.                             If this.oReport.aTables.Size = 1 And;
  386.                                             Upper(Right(this.oReport.DataFile, 4)) # ".QBE"
  387.                                 this.oReport.aTables[1].TableName = this.oReport.DataFile
  388.                             EndIf
  389.                             // Now set up the Query objects based on information
  390.                             // obtained from the .RPT and .QBE file (if any)
  391.                             For nTemp = this.oReport.aTables.Size To 1 Step -1
  392.                                 If Len(this.oReport.aTables[nTemp].TableName) = 0
  393.                                     this.oReport.aTables[nTemp].TableName =;
  394.                                                             this.oReport.DataPath +;
  395.                                                             this.oReport.aTables[nTemp].Alias
  396.                                 EndIf
  397.                                 // Create a new query template object
  398.                                 this.CurrentObject =;
  399.                                                 New xQuery(this.oReport.NextName(;
  400.                                                         this.oReport.aTables[nTemp].Alias))
  401.                                 // Save it in an array of queries for later reference
  402.                                 this.aQueries.Add(this.CurrentObject)
  403.                                 this.CurrentObject.TableName =;
  404.                                                     this.oReport.aTables[nTemp].TableName
  405.                                 this.CurrentObject["Top"] = 50
  406.                                 this.CurrentObject["Left"] = 50 +;
  407.                                             ((this.oReport.aTables.Size - nTemp) * 500)
  408.                                 this.CurrentObject["SQL"] = "'SELECT * FROM " + '"' +;
  409.                                                 this.oReport.aTables[nTemp].TableName + ["']
  410.                                 oTemp = this.CurrentObject
  411.                                 // Add the Query template to the .REP array cluster
  412.                                 // as a child object of the report class.
  413.                                 this.AddToReport()
  414.                                 this.CurrentContainer = oTemp
  415.                                 If Not IsBlank(this.oReport.aTables[nTemp].Tag)
  416.                                     this.CurrentObject = New xRowSet()
  417.                                     this.CurrentObject["IndexName"] = '"' +;
  418.                                                     this.oReport.aTables[nTemp].Tag + '"'
  419.                                     this.oReport["AutoSort"] = False
  420.                                     this.CurrentContainer.Indexed = True
  421.                                 EndIf
  422.                                 // If this table is a child table in a relation, set
  423.                                 // the links in IndexName, MasterRowset and MasterFields.
  424.                                 If Not IsBlank(this.oReport.aTables[nTemp].ParentTable)
  425.                                     this.lRelatedTables = True
  426.                                     For lTemp = 1 To this.aQueries.Size
  427.                                         If this.oReport.aTables[nTemp].ParentTable $;
  428.                                                                 this.aQueries[lTemp].xName
  429.                                             If Type("this.CurrentObject") == "U"
  430.                                                 this.CurrentObject = New xRowSet()
  431.                                             EndIf
  432.                                             this.CurrentObject["MasterRowset"] = "form." +;
  433.                                                     this.oReport.aTables[nTemp].ParentTable +;
  434.                                                                                             "1.Rowset"
  435.                                             this.CurrentObject["MasterFields"] = '"' +;
  436.                                                     this.oReport.aTables[nTemp].ParentField +;
  437.                                                                                                     '"'
  438.                                             Exit
  439.                                         EndIf
  440.                                     EndFor
  441.                                 EndIf
  442.                                 this.AddToReport()
  443.                                 this.CurrentContainer = this.oReport
  444.                             EndFor  // Repeat to create a Query template for each table
  445.                             // Message streamed to .REP header if related tables exist
  446.                             If this.lRelatedTables
  447.                                 this.aErrors.Add(this.oForm.oLang.iText("TableRelations"))
  448.                             EndIf
  449.                             // Add the Printer template to the .REP array cluster
  450.                             // as a child object of the report class.
  451.                             this.CurrentObject = this.oPrinter
  452.                             this.AddToReport()
  453.                             // Add the PageTemplate template to the .REP array cluster
  454.                             // as a child object of the report class.
  455.                             this.CurrentObject = this.oPageTemplate
  456.                             this.AddToReport()
  457.                             // Make the PageTemplate the current container
  458.                             this.CurrentContainer = this.oPageTemplate
  459.                             // Report header is implemented at the top of
  460.                             // the PageTemplate.
  461.                         EndIf
  462.                         this.ReadingGrpHeader = this.BandID = CRWBAND_GRPHEADER
  463.                         // If the current band being read is a group header band
  464.                         If this.ReadingGrpHeader
  465.                             // Make the StreamSource the current container
  466.                             this.CurrentContainer = this.oStreamSource
  467.                             // Instantiate a Group template
  468.                             this.oGroup =;
  469.                                         New xGroup(this.oStreamSource.NextName("GROUP"))
  470.                             this.oGroup["GroupBy"] = '"' + this.GroupBy + '"'
  471.                             this.aGroups.Add(this.oGroup)  // Save for later reference
  472.                             this.aGroups.CurrentGroup = this.aGroups.Size
  473.                             // Add the Group to the .REP array cluster
  474.                             // as a child of the StreamSource
  475.                             this.CurrentObject = this.oGroup
  476.                             this.AddToReport()
  477.                             this.CurrentContainer = this.oGroup.HeaderBand
  478.                         EndIf
  479.                         this.ReadingRptDetail = this.BandID = CRWBAND_RPTDETAIL
  480.                         // If the current band being read is the report detail band
  481.                         If this.ReadingRptDetail
  482.                             // Time to add the StreamSource to the .REP array cluster
  483.                             this.CurrentContainer = this.oReport
  484.                             this.CurrentObject = this.oStreamSource
  485.                             this.AddToReport()
  486.                             this.CurrentContainer = this.oStreamSource
  487.                             // Add a detail band as a child of the StreamSource
  488.                             this.CurrentObject = New xBand("DETAIL")
  489.                             this.AddToReport()
  490.                             // Make the detail band the current container
  491.                             this.CurrentContainer = this.oStreamSource.Objects;
  492.                                                             [this.oStreamSource.Objects.Size]
  493.                             // Save a reference to the detail band for later use
  494.                             this.oDetailBand = this.CurrentContainer
  495.                         EndIf
  496.                         this.ReadingGrpFooter = this.BandID = CRWBAND_GRPFOOTER
  497.                         // If the current band being read is a group footer band
  498.                         If this.ReadingGrpFooter
  499.                             this.oGroup = this.aGroups[this.aGroups.CurrentGroup--]
  500.                             this.CurrentContainer = this.oGroup.FooterBand
  501.                         EndIf
  502.                         this.ReadingGrndTotal = this.BandID = CRWBAND_GRNDTOTAL
  503.                         // If the current band being read is a grand total band
  504.                         If this.ReadingGrndTotal
  505.                             // Implement grand total band as ReportGroup.FooterBand
  506.                             this.CurrentContainer = this.oReport
  507.                             this.oReportGroup = New xReportGroup()
  508.                             this.CurrentObject = this.oReportGroup
  509.                             this.AddToReport()
  510.                             this.CurrentContainer = this.oReportGroup.FooterBand
  511.                         EndIf
  512.                         this.ReadingRptFooter = this.BandID = CRWBAND_RPTFOOTER
  513.                         // If the current band being read is the report footer band
  514.                         If this.ReadingRptFooter
  515.                             // Report footer is implemented at the bottom of
  516.                             // the PageTemplate
  517.                             this.CurrentContainer = this.oPageTemplate
  518.                         EndIf
  519.                         this.CurrentBand = this.aCRWBands[this.aCRWBands.Size]
  520.                         this.CurrentBand.ID = this.BandID
  521.                         this.CurrentBand.Container = this.CurrentContainer
  522.                         this.CurrentObject = this.CurrentBand
  523.  
  524.                     Case this.RecID = HToI("1003")  // CRW BandLine
  525.                         // This case is encountered once for each .RPT band line
  526.                         // to indicate the start of a new line. After 1003, other
  527.                         // record types (100A, 1013, 102A, 1009, etc) are encountered
  528.                         // which further describe the band line and any text placed
  529.                         // directly on the band line. The end of the band line is
  530.                         // indicated by 1009.
  531.                         this.RecTypeDescr = "Band Line"
  532.                         // Add any previously constructed object to the .REP array cluster
  533.                         this.AddToReport()
  534.                         this.ReadRecord()
  535.                         this.ReadingLine = True
  536.                         aLines = this.aCRWBands[this.aCRWBands.Size]
  537.                         aLines.Add(New CRWLine())
  538.                         this.CurrentLine = aLines[aLines.Size]
  539.                         this.ObjectsLine = this.CurrentLine
  540.                         this.CurrentLine.BandID = this.CurrentBand.ID
  541.                         this.CurrentObject = this.CurrentLine
  542.                         // Initialize HTML tracking variables to defaults
  543.                         this.RawHText = ""
  544.                         this.CurColor = HTML_DEFCOLOR
  545.                         this.CurFName = HTML_DEFFACE
  546.                         this.CurFBold = HTML_DEFBOLD
  547.                         this.CurFItal = HTML_DEFITAL
  548.                         this.CurFUnln = HTML_DEFUNLN
  549.  
  550.                     Case this.RecID = HToI("1004")  // CRW Band Line Text Count
  551.                         // Indicates the number of characters (including spaces)
  552.                         // contained directly on the band line.
  553.                         this.RecTypeDescr = "Band Line Text Count"
  554.                         this.ReadRecord()
  555.                         // Save character count for case 1005
  556.                         this.TextCount = MAKEU16(this.xREC, 1)
  557.  
  558.                     Case this.RecID = HToI("1005")  // CRW BandLine Text
  559.                         // This is the actual text contained directly on the band line.
  560.                         this.RecTypeDescr = "Band Line Text"
  561.                         this.ReadRecord()
  562.                         cTemp = STRIPNULL(this.xREC)
  563.                         // If the length doesn't match, the .RPT file is corrupt.
  564.                         If Len(cTemp) # this.TextCount
  565.                             this.oError.LineNo = LineNo() - 1
  566.                             this.oError.Filename = Program()
  567.                             this.oError.Code = 10012
  568.                             Throw this.oError
  569.                         EndIf
  570.                         // Save the text
  571.                         this.RawHText += cTemp
  572.                         // Compute the height and width of the text.
  573.                         nTemp = this.GetItemSize(cTemp)
  574.                         // If the text height is greater than the line height
  575.                         If nTemp > this.CurrentLine.Height
  576.                             this.CurrentLine.Height = nTemp
  577.                         EndIf
  578.                         // Add the width of the text to the current line's width
  579.                         this.CurrentLine.Width += this.ItemWidth
  580.                         // Add the text to the current line's HTML text stream.
  581.                         this.CurrentLine.HTMLText += cTemp
  582.  
  583.                 Case this.RecID = HToI("1006")  // CRW Text Field
  584.                         this.RecTypeDescr = "Text Field"
  585.                         // Add any previously created template to the .REP array cluster
  586.                         this.AddToReport()
  587.                         this.ReadRecord()
  588.                         // Create a new Text template
  589.                         this.CurrentObject = New xText()
  590.                         nTemp = MAKEU16(this.xREC, 1)
  591.                         // If the text field's Left value is not equal to 0.
  592.                         If nTemp # 0
  593.                             this.CurrentObject["Left"] = nTemp
  594.                         EndIf
  595.                         // Extract the text field's width
  596.                         this.CurrentObject["Width"] = MAKEU16(this.xREC, 3)
  597.                         // Extract SuppressIfDuplicate
  598.                         lTemp = MAKEU16(this.xREC, 5) # 0
  599.                         If lTemp
  600.                             this.CurrentObject["SuppressIfDuplicate"] = True
  601.                         EndIf
  602.                         // Extract Hide When Printing
  603.                         If MAKEU16(this.xREC, 7) # 0
  604.                             this.CurrentObject["Visible"] = False
  605.                         EndIf
  606.                         // Extract horizontal alignment
  607.                         nTemp = MAKEU16(this.xREC, 9)
  608.                         If nTemp > 1
  609.                             this.CurrentObject["AlignHorizontal"] = Int(nTemp - 1)
  610.                         EndIf
  611.                         this.SaveVarHeight = MAKEU16(this.xREC, 77)
  612.  
  613.                     Case this.RecID = HToI("1007")  // Unknown
  614.                         // Associated to various objects.
  615.                         this.RecTypeDescr = "Unknown Record Type"
  616.                         this.ReadRecord(True)
  617.  
  618.                     Case this.RecID = HToI("1008")  // CRW Text Field and Image DataLink
  619.                         // Text field is DataLinked to a table field
  620.                         //                - OR -
  621.                         // an ORDER BY/GROUP BY specification.
  622.                         this.RecTypeDescr = "Text Field DataLink"
  623.                         this.ReadRecord()
  624.                         this.xREC = STRIPNULL(this.xREC)
  625.                         this.xREC = Right(this.xREC,;
  626.                                                         Len(this.xREC) - At(".", this.xREC))
  627.                         cTemp = SubStr(this.xREC, RAt(">", this.xREC) + 1)
  628.                         // Also see 1010 and 1012 for the following.
  629.                         If Type("this.CurrentObject") == "O"    // Text field DataLink
  630.                             oTemp = this.CurrentObject
  631.                             // Assign a name to the object as 'TEXT' + table field name
  632.                             oTemp.xName =;
  633.                                 this.CurrentContainer.NextName(oTemp.xClassName + cTemp)
  634.                             If oTemp.xClassName == "IMAGE"
  635.                                 cTemp = this.ConvertField(this.xREC)
  636.                                 cTemp = SubStr(cTemp, At("FORM.", Upper(cTemp)))
  637.                                 oTemp["DataSource"] = Left(cTemp, At("]", cTemp))
  638.                             Else
  639.                                 // Map the Text property using VdB RowSet syntax
  640.                                 oTemp["Text"] = this.ConvertField(this.xREC)
  641.                                 // Get field data type
  642.                                 lTemp = this.FieldType(this.xREC)
  643.                                 // If numeric data type, right-align it (CRW numeric default)
  644.                                 // if the alignment was not specified in the .RPT
  645.                                 If lTemp == "N" And Not oTemp.IsKey("AlignHorizontal")
  646.                                     oTemp["AlignHorizontal"] = 2
  647.                                 EndIf
  648.                                 // If memo field and print on multiple lines
  649.                                 If lTemp == "M" And this.SaveVarHeight = 0
  650.                                     this.SaveVarHeight = 1
  651.                                 EndIf
  652.                                 // If print on multiple lines
  653.                                 If this.SaveVarHeight > 0
  654.                                     oTemp["VariableHeight"] = True
  655.                                 Else
  656.                                     oTemp["Wrap"] = False
  657.                                 EndIf
  658.                                 // If this is an aggregate text field (See 1010), then
  659.                                 // remap the Text property for aggregate computation.
  660.                                 If Not IsBlank(oTemp.AgType)
  661.                                     If Left(oTemp.AgType, 2) # "UN"
  662.                                         cTemp = this.ConvertField(this.xREC)
  663.                                         If this.ReadingGrpHeader Or this.ReadingGrpFooter
  664.                                             Do While At("THIS.FORM.", Upper(cTemp)) > 0
  665.                                                 cTemp = Stuff(cTemp,;
  666.                                                                 At("THIS.FORM.", Upper(cTemp)),;
  667.                                                                         10, "this.parent.parent.")
  668.                                             EndDo
  669.                                             oTemp["Text"] = "{|| this.Parent.Parent." +;
  670.                                                                 oTemp.AgType + "(" + cTemp + ")}"
  671.                                         ElseIf this.ReadingGrndTotal
  672.                                             Do While At("THIS.FORM.", Upper(cTemp)) > 0
  673.                                                 cTemp = Stuff(cTemp,;
  674.                                                                 At("THIS.FORM.", Upper(cTemp)),;
  675.                                                                         10, "this.parent.")
  676.                                             EndDo
  677.                                             oTemp["Text"] = "{|| this.Parent.Parent." +;
  678.                                                                 oTemp.AgType + "(" + cTemp + ")}"
  679.                                         EndIf
  680.                                     Else  // Unsupported aggregate function
  681.                                         // Place error msg in Text property
  682.                                         oTemp["Text"] = '"' + oTemp.AgError + '"'
  683.                                         // and in messages streamed to report header.
  684.                                         this.aErrors.Add(oTemp.AgError + " - " + oTemp.xName)
  685.                                     EndIf
  686.                                 EndIf
  687.                                 oTemp.SetFont((this))
  688.                             EndIf
  689.                         ElseIf this.ReadingOrdInfo     // Order By/Group By (Also see 1011)
  690.                             this.OrderBy = cTemp
  691.                             cTemp = Left(this.xREC, At("->", this.xREC) - 1)
  692.                             // Add the OrderBy field to the correct table field array
  693.                             For nTemp = 1 To this.oReport.aTables.Size
  694.                                 If this.oReport.aTables[nTemp].Alias == cTemp
  695.                                     this.oReport.aTables[nTemp].aOrders.Add(this.OrderBy,;
  696.                                                                                         this.SortOrder)
  697.                                     If this.ReadingGrpInfo  // See 1012
  698.                                         this.oReport.aTables[nTemp].aGroups.Add(this.OrderBy)
  699.                                         this.GroupBy = this.OrderBy
  700.                                         this.cStreamQuery =;
  701.                                                 Left(this.xREC, At("->", this.xREC) - 1) + "1"
  702.                                     EndIf
  703.                                     Exit
  704.                                 EndIf
  705.                             EndFor
  706.                             this.ReadingOrdInfo = False
  707.                             this.ReadingGrpInfo = False
  708.                         EndIf
  709.  
  710.                     Case this.RecID = HToI("1009")  // Band Line End
  711.                         // As 1003 indicates the start of a band line, 1009 indicates
  712.                         // the end of the band line. It is now necessary to assemble
  713.                         // the elements needed to construct a Text template and assign
  714.                         // the HTML text stream to the Text property.
  715.                         this.RecTypeDescr = "Band Line End"
  716.                         this.ReadRecord()
  717.                         this.ReadingLine = False
  718.                         // If there is actual text other than just white space
  719.                         If Len(Trim(this.RawHText)) > 0
  720.                             // Create a new Text template to carry the band line text
  721.                             // to the .REP array cluster.
  722.                             this.CurrentObject = New xText()
  723.                             this.CurrentObject.xName =;
  724.                                                     this.CurrentContainer.NextName("TEXT")
  725.                             // Set the Height to the greatest height of the text
  726.                             // elements on the band line.
  727.                             this.CurrentObject["Height"] = this.CurrentLine.Height
  728.                             // Set the Width to the accumulated width of the text
  729.                             // elements on the band line.
  730.                             this.CurrentObject["Width"] = this.CurrentLine.Width
  731.                             // Set the default color.
  732.                             this.CurrentObject["ColorNormal"] = '"BtnText"'
  733.                             // Turn off wrap
  734.                             this.CurrentObject["Wrap"] = False
  735.                             // Now close the HTML text tags as necessary.
  736.                             If this.CurColor # HTML_DEFCOLOR
  737.                                 this.CurrentLine.HTMLText += '</font>'
  738.                             EndIf
  739.                             If this.CurFUnln # HTML_DEFUNLN
  740.                                 this.CurrentLine.HTMLText += '</u>'
  741.                             EndIf
  742.                             If this.CurFItal # HTML_DEFITAL
  743.                                 this.CurrentLine.HTMLText += '</i>'
  744.                             EndIf
  745.                             If this.CurFBold # HTML_DEFBOLD
  746.                                 this.CurrentLine.HTMLText += '</b>'
  747.                             EndIf
  748.                             If this.CurFSize # HTML_DEFFNSZ
  749.                                 this.CurrentLine.HTMLText += '</font>'
  750.                             EndIf
  751.                             If this.CurFName # HTML_DEFFACE
  752.                                 this.CurrentLine.HTMLText += '</font>'
  753.                             EndIf
  754.                             this.CurrentObject["Text"] = this.CurrentLine.HTMLText +;
  755.                                                                     "</pre>'"
  756.                             // Add the new Text template to the .REP array cluster.
  757.                             this.AddToReport()
  758.                         Else                            // No real text on the line
  759.                             // Setup a Blank to take up vertical space.
  760.                             this.CurrentObject =;
  761.                                         New xBlank(this.CurrentContainer.NextName("BLANK"))
  762.                         EndIf
  763.                         this.RawHText = ""
  764.  
  765.                     Case this.RecID = HToI("100A")  // Font descriptor
  766.                         // This case is used to describe the font attributes
  767.                         // (name, size, bold, italic, underline, strikeout) for
  768.                         // text fields and band line text.
  769.                         this.RecTypeDescr = "Font Descriptor"
  770.                         this.ReadRecord()
  771.                         this.FontRec = this.xREC
  772.                         // Extract required font information
  773.                         this.FontName = Left(this.xREC, At(Chr(0), this.xREC) - 1)
  774.                         this.FontSize = MAKEU16(this.xREC, 39)
  775.                         this.FontBold = MAKEU16(this.xREC, 42)
  776.                         nTemp = MAKE8(this.xREC, 41)
  777.                         this.FontItalic =        BitSet(nTemp, 0)
  778.                         this.FontUnderline =    BitSet(nTemp, 1)
  779.                         this.FontStrikeout =    BitSet(nTemp, 2)
  780.                         // Compute text height using the font settings
  781.                         nTemp = this.GetItemSize("H")
  782.                         If nTemp > this.CurrentLine.Height
  783.                             // Adjust line height accordingly
  784.                             this.CurrentLine.Height = nTemp
  785.                         EndIf
  786.                         // If currently reading a band line (ie; 1003 but no 1009 yet),
  787.                         // then adjust HTML stream for any font changes from current
  788.                         // font settings.
  789.                         If this.ReadingLine
  790.                             If this.CurFName # this.FontName And;
  791.                                             this.CurFName # HTML_DEFFACE
  792.                                 this.CurrentLine.HTMLText += '</font>'
  793.                                 this.CurFName = HTML_DEFFACE
  794.                             EndIf
  795.                             If this.CurFName = HTML_DEFFACE And;
  796.                                             this.FontName # this.CurFName
  797.                                 this.CurrentLine.HTMLText += '<font face="' +;
  798.                                                                 this.FontName + '">'
  799.                             EndIf
  800.                             this.CurFName = this.FontName
  801.                             Do Case
  802.                                 Case this.FontSize > 33
  803.                                     cTemp = "+4"
  804.                                 Case this.FontSize > 21
  805.                                     cTemp = "+3"
  806.                                 Case this.FontSize > 15
  807.                                     cTemp = "+2"
  808.                                 Case this.FontSize > 11
  809.                                     cTemp = "+1"
  810.                                 Case this.FontSize > 9
  811.                                     cTemp = "0"
  812.                                 Case this.FontSize > 7
  813.                                     cTemp = "-1"
  814.                                 Otherwise
  815.                                     cTemp = "-2"
  816.                             EndCase
  817.                             If this.CurFSizeTag # cTemp And this.CurFSizeTag # "0"
  818.                                 this.CurrentLine.HTMLText += '</font>'
  819.                                 this.CurFSizeTag = "0"
  820.                             EndIf
  821.                             If this.CurFSizeTag = "0" And cTemp # this.CurFSizeTag
  822.                                 this.CurrentLine.HTMLText += '<font size=' + cTemp + '>'
  823.                             EndIf
  824.                             this.CurFSizeTag = cTemp
  825.  
  826.                             If this.CurFBold # this.FontBold And;
  827.                                             this.CurFBold # HTML_DEFBOLD
  828.                                 this.CurrentLine.HTMLText += '</b>'
  829.                                 this.CurFBold = HTML_DEFBOLD
  830.                             EndIf
  831.                             If this.CurFBold = HTML_DEFBOLD And;
  832.                                             this.FontBold # this.CurFBold
  833.                                 this.CurrentLine.HTMLText += '<b>'
  834.                             EndIf
  835.                             this.CurFBold = this.FontBold
  836.  
  837.                             If this.CurFItal # this.FontItalic And;
  838.                                             this.CurFItal # HTML_DEFITAL
  839.                                 this.CurrentLine.HTMLText += '</i>'
  840.                                 this.CurFItal = HTML_DEFITAL
  841.                             EndIf
  842.                             If this.CurFItal = HTML_DEFITAL And;
  843.                                             this.FontItalic # this.CurFItal
  844.                                 this.CurrentLine.HTMLText += '<i>'
  845.                             EndIf
  846.                             this.CurFItal = this.FontItalic
  847.  
  848.                             If this.CurFUnln # this.FontUnderline And;
  849.                                             this.CurFUnln # HTML_DEFUNLN
  850.                                 this.CurrentLine.HTMLText += '</u>'
  851.                                 this.CurFUnln = HTML_DEFUNLN
  852.                             EndIf
  853.                             If this.CurFUnln = HTML_DEFUNLN And;
  854.                                             this.FontUnderline # this.CurFUnln
  855.                                 this.CurrentLine.HTMLText += '<u>'
  856.                             EndIf
  857.                             this.CurFUnln = this.FontUnderline
  858.                         EndIf
  859.  
  860.                     Case this.RecID = HToI("100B")  // Formula count
  861.                         this.RecTypeDescr = "Formula Count"
  862.                         this.ReadRecord()
  863.                         // Save formula count for later verification after
  864.                         // all formulas are read from .RPT file.
  865.                         this.oReport.FormulaCount = MAKEU16(this.xREC, 1)
  866.  
  867.                     Case this.RecID = HToI("100C")  // Formula descriptor
  868.                         // We can skip this. We only need the formula name and formula.
  869.                         this.RecTypeDescr = "Formula Descriptor"
  870.                         this.ReadRecord(True)
  871.  
  872.                     Case this.RecID = HToI("100D")  // Formula name
  873.                         // Record ID 100D is used to identify the formula name.
  874.                         // It is also used later to associate the formula name to
  875.                         // a text object.
  876.                         this.RecTypeDescr = "Formula Name"
  877.                         this.ReadRecord()
  878.                         cTemp = Left(this.xREC, Len(this.xREC) - 1)
  879.                         // Drop extraneous carriage returns and linefeeds.
  880.                         Do While Right(cTemp, 1) = LF Or;
  881.                                     Right(cTemp, 1) = CR
  882.                             cTemp = Left(cTemp, Len(cTemp) - 1)
  883.                         EndDo
  884.                         If this.oReport.aaFormulas.Count() # this.oReport.FormulaCount
  885.                         // If we are still reading formulas
  886.                             this.FormulaName = cTemp
  887.                         ElseIf Type("this.CurrentObject") # "U"
  888.                         // This formula name is linking a formula to a text field
  889.                             oTemp = this.CurrentObject
  890.                             // Now that we know the current Text template will not be
  891.                             // linked to a table field, assign a name to it using
  892.                             // 'TEXT' + next available number.
  893.                             oTemp.xName = this.CurrentContainer.NextName("TEXT")
  894.                             // Assign the Text property to the actual formula.
  895.                             oTemp["Text"] = this.oReport.aaFormulas[cTemp]
  896.                             // Stream a formula message to .REP header.
  897.                             this.aErrors.Add(this.oForm.oLang.iText("HasFormulas") +;
  898.                                                                             " - " + oTemp.xName)
  899.                             // If this is an aggregate field based on a formula (See 1010)
  900.                             // then remap the Text property to the aggregate operation.
  901.                             If Not IsBlank(oTemp.AgType)
  902.                                 If Left(oTemp.AgType, 2) # "UN"
  903.                                     cTemp = oTemp["Text"]
  904.                                     If this.ReadingGrpHeader Or this.ReadingGrpFooter
  905.                                         Do While At("THIS.FORM.", Upper(cTemp)) > 0
  906.                                             cTemp = Stuff(cTemp,;
  907.                                                                 At("THIS.FORM.", Upper(cTemp)),;
  908.                                                                         10, "this.parent.parent.")
  909.                                         EndDo
  910.                                         oTemp["Text"] = "{|| this.Parent.Parent." +;
  911.                                                                 oTemp.AgType + "(" + cTemp + ")}"
  912.                                     ElseIf this.ReadingGrndTotal
  913.                                         Do While At("THIS.FORM.", Upper(cTemp)) > 0
  914.                                             cTemp = Stuff(cTemp,;
  915.                                                                 At("THIS.FORM.", Upper(cTemp)),;
  916.                                                                         10, "this.parent.")
  917.                                         EndDo
  918.                                         oTemp["Text"] = "{|| this.Parent.Parent." +;
  919.                                                                 oTemp.AgType + "(" + cTemp + ")}"
  920.                                     EndIf
  921.                                 Else
  922.                                     oTemp["Text"] = '"' + oTemp.AgError + '"'
  923.                                 EndIf
  924.                             EndIf
  925.                             // Set the font attributes and height for the Text template.
  926.                             // See the class RepObjBase::SetFont method
  927.                             oTemp.SetFont((this))
  928.                             // If print on multiple lines
  929.                             If this.SaveVarHeight > 0
  930.                                 oTemp["VariableHeight"] = True
  931.                             Else
  932.                                 oTemp["Wrap"] = False
  933.                             EndIf
  934.                         Else
  935.                             this.aErrors.Add(this.oForm.oLang.iText("HasGroupFormula") +;
  936.                                                                                         " - " + cTemp)
  937.                         EndIf
  938.  
  939.                     Case this.RecID = HToI("100E")  // Formula
  940.                         // This is the actual formula referenced by the name
  941.                         // specified in record ID 100D. These formulas are saved
  942.                         // in an array (oReport.aaFormulas) for later use when
  943.                         // linking to objects in the report.
  944.                         this.RecTypeDescr = "Formula"
  945.                         this.ReadRecord()
  946.                         cTemp = Left(this.xREC, Len(this.xREC) - 1)
  947.                         // Drop extraneous carriage returns and linefeeds.
  948.                         Do While Right(cTemp, 1) = LF Or;
  949.                                     Right(cTemp, 1) = CR
  950.                             cTemp = Left(cTemp, Len(cTemp) - 1)
  951.                         EndDo
  952.                         // Save the formula for later use.
  953.                         this.oReport.aaFormulas[this.FormulaName] =;
  954.                                             this.ConvertField(this.ConvertFormula(cTemp))
  955.  
  956.                     Case this.RecID = HToI("100F")  // Record selection criteria
  957.                         // This case describes any record selection criteria
  958.                         // specified in the .RPT file.
  959.                         this.RecTypeDescr = "Record Selection Criteria"
  960.                         this.ReadRecord()
  961.                         cTemp = STRIPNULL(this.xREC)
  962.                         If Not Empty(cTemp)
  963.                             this.aErrors.Add(this.oForm.oLang.iText("RecSelCrit"))
  964.                             this.aErrors.Add("   " + cTemp)
  965.                         EndIf
  966.  
  967.                     Case this.RecID = HToI("1010")  // Aggregate Summary Operation Type
  968.                         // This case specifies an aggregate operation type to be
  969.                         // applied to a table field or formula linked to a Text field.
  970.                         this.RecTypeDescr = "Aggregate Summary Operation Type"
  971.                         this.ReadRecord()
  972.                         nTemp = MAKEU16(this.xREC, 1)
  973.                         Do Case
  974.                             Case nTemp = 0                    // Sum
  975.                                 this.CurrentObject.AgType = "agSum"
  976.                             Case nTemp = 1                    // Average
  977.                                 this.CurrentObject.AgType = "agAverage"
  978.                             Case nTemp = 2                    // Sample Variance
  979.                                 this.CurrentObject.AgType = "agVariance"
  980.                             Case nTemp = 3                    // Sample Standard Deviation
  981.                                 this.CurrentObject.AgType = "agStdDeviation"
  982.                             Case nTemp = 4                    // Max
  983.                                 this.CurrentObject.AgType = "agMax"
  984.                             Case nTemp = 5                    // Min
  985.                                 this.CurrentObject.AgType = "agMin"
  986.                             Case nTemp = 6                    // Count
  987.                                 this.CurrentObject.AgType = "agCount"
  988.                      // These CRW aggregates are not supported
  989.                             Case nTemp = 7                    // Population Variance
  990.                                 this.CurrentObject.AgType = "UNSUPPORTED"
  991.                                 this.CurrentObject.AgError =;
  992.                                                             this.oForm.oLang.iText("agPopVar")
  993.                             Case nTemp = 8                    // Population Standard Deviation
  994.                                 this.CurrentObject.AgType = "UNSUPPORTED"
  995.                                 this.CurrentObject.AgError =;
  996.                                                             this.oForm.oLang.iText("agPopDev")
  997.                             Case nTemp = 9                    // Distinct Count
  998.                                 this.CurrentObject.AgType = "UNSUPPORTED"
  999.                                 this.CurrentObject.AgError =;
  1000.                                                             this.oForm.oLang.iText("agDisCnt")
  1001.                             Otherwise                        // I have no idea.
  1002.                                 this.CurrentObject.AgType = "UNKNOWN"
  1003.                                 this.CurrentObject.AgError =;
  1004.                                                             this.oForm.oLang.iText("agUnknown")
  1005.                         EndCase
  1006.  
  1007.                     Case this.RecID = HToI("1011")  // Report Fields Sort Direction
  1008.                         // This case specifies the sort direction.
  1009.                         // (Also see 1008)
  1010.                         this.RecTypeDescr = "Report Fields Sort Direction"
  1011.                         this.ReadRecord()
  1012.                         this.ReadingOrdInfo = True
  1013.                         this.SortOrder = IIf(MAKEU16(this.xREC, 1) = 0, "ASC", "DESC")
  1014.  
  1015.                     Case this.RecID = HToI("1012")  // Group Section Sort Direction
  1016.                         // This case specifies the sort direction for a group.
  1017.                         // (Also see 1008)
  1018.                         this.RecTypeDescr = "Group Section Sort Direction"
  1019.                         this.AddToReport()
  1020.                         this.ReadRecord()
  1021.                         this.ReadingOrdInfo = True
  1022.                         this.ReadingGrpInfo = True
  1023.                         this.SortOrder = IIf(MAKEU16(this.xREC, 7) = 0, "ASC", "DESC")
  1024.  
  1025.                     Case this.RecID = HToI("1013")  // CRW BandLine.Text Tab
  1026.                         // Each occurrence of this case adds a tab character
  1027.                         // to the current HTML text stream for the current
  1028.                         // band line.
  1029.                         this.RecTypeDescr = "Band Line.Text Tab"
  1030.                         this.ReadRecord(True)
  1031.                         this.CurrentLine.HTMLText += Chr(9)
  1032.                         this.RawHText += Chr(9)
  1033.  
  1034.                     Case this.RecID = HToI("1014")  // Special Field Type
  1035.                         // This case specifies special field types in the .RPT file.
  1036.                         this.RecTypeDescr = "Special Field Type"
  1037.                         this.ReadRecord()
  1038.                         oTemp = this.CurrentObject
  1039.                         // Now that we know the current Text template will not be
  1040.                         // linked to a table field, assign a name to it using
  1041.                         // 'TEXT' + next available number.
  1042.                         oTemp.xName = this.CurrentContainer.NextName("TEXT")
  1043.                         // Extract special field type and process based on type
  1044.                         nTemp = MAKEU16(this.xREC, 1)
  1045.                         Do Case
  1046.                             Case nTemp = 0                    // Date
  1047.                                 oTemp["Text"] = "{|| DToC(Date())}"
  1048.                             Case nTemp = 4                    // Record Number (unsupported)
  1049.                                 oTemp["Text"] = '"' +;
  1050.                                                     this.oForm.oLang.iText("sfRecNo") + '"'
  1051.                                 this.aErrors.Add(this.oForm.oLang.iText("sfRecNo") +;
  1052.                                                                             " - " + oTemp.xName)
  1053.                             Case nTemp = 5                    // Page Number
  1054.                                 oTemp["Text"] = "{|| Str(form.reportPage, 5)}"
  1055.                             Case nTemp = 6                    // Group Number (unsupported)
  1056.                                 oTemp["Text"] = '"' +;
  1057.                                                     this.oForm.oLang.iText("sfGrpNum") + '"'
  1058.                                 this.aErrors.Add(this.oForm.oLang.iText("sfGrpNum") +;
  1059.                                                                             " - " + oTemp.xName)
  1060.                             Otherwise                        // (unknown special field)
  1061.                                 oTemp["Text"] = '"' +;
  1062.                                                     this.oForm.oLang.iText("sfUnknown") + '"'
  1063.                                 this.aErrors.Add(this.oForm.oLang.iText("sfUnknown") +;
  1064.                                                                             " - " + oTemp.xName)
  1065.                         EndCase
  1066.                         // Set the font attributes and height for the Text template.
  1067.                         // See the class RepObjBase::SetFont method
  1068.                         oTemp.SetFont((this))
  1069.  
  1070.                     Case this.RecID = HToI("1016")  // Printer
  1071.                         // This case specifies printer settings.
  1072.                         // See the xPrinter class for additional information.
  1073.                         // For Win API programmers, this data is in a DEVMODE
  1074.                         // structure format. Consult Win API documentation.
  1075.                         this.RecTypeDescr = "Printer DEVMODE"
  1076.                         this.ReadRecord()
  1077.                         // Extract printer settings and save to Printer template.
  1078.                         nTemp = MAKEU16(this.xREC, IND_DMPRINTQUALITY)
  1079.                         nPQuality = IIf(nTemp < 201, 1,;
  1080.                                IIf(nTemp < 301, 2,;
  1081.                                    IIf(nTemp < 600, 3, 4)))
  1082.                         nTemp = Int(MAKEU32(this.xREC, IND_DMFIELDS))
  1083.                         this.oPrinter["Color"] =;
  1084.                                             IIf(BitAnd(nTemp, DM_COLOR) > 0,;
  1085.                                                 MAKEU16(this.xREC, IND_DMCOLOR), 0)
  1086.                         this.oPrinter["Copies"] =;
  1087.                                             IIf(BitAnd(nTemp, DM_COPIES) > 0,;
  1088.                                                 MAKEU16(this.xREC, IND_DMCOPIES), 1)
  1089.                         this.oPrinter["Duplex"] =;
  1090.                                             IIf(BitAnd(nTemp, DM_DUPLEX) > 0,;
  1091.                                                 MAKEU16(this.xREC, IND_DMDUPLEX), 0)
  1092.                         this.oPrinter["Orientation"] =;
  1093.                                             IIf(BitAnd(nTemp, DM_ORIENTATION) > 0,;
  1094.                                                 MAKEU16(this.xREC, IND_DMORIENTATION), 0)
  1095.                         this.oPrinter["PaperSize"] =;
  1096.                                             IIf(BitAnd(nTemp, DM_ORIENTATION) > 0,;
  1097.                                                 MAKEU16(this.xREC, IND_DMPAPERSIZE),;
  1098.                                                 DMPAPER_LETTER)
  1099.                         this.oPrinter["PaperSource"] =;
  1100.                                             IIf(BitAnd(nTemp, DM_DEFAULTSOURCE) > 0,;
  1101.                                                 MAKEU16(this.xREC, IND_DMDEFAULTSOURCE),;
  1102.                                                 DMBIN_MANUAL)
  1103.                         this.oPrinter["PrinterName"] = '"' +;
  1104.                                         Left(this.xREC, At(Chr(0), this.xREC) - 1) + '"'
  1105.                         this.oPrinter["PrinterSource"] = 2
  1106.                         this.oPrinter["Resolution"] =;
  1107.                                             IIf(BitAnd(nTemp, DM_PRINTQUALITY) > 0,;
  1108.                                                 nPQuality, 0)
  1109.                         this.oPrinter["TrueTypeFonts"] =;
  1110.                                             IIf(BitAnd(nTemp, DM_TTOPTION) > 0,;
  1111.                                                 MAKEU16(this.xREC, IND_DMTTOPTION), 0)
  1112.  
  1113.                     Case this.RecID = HToI("1017")  // Text Field border style BG color
  1114.                         // This case describes a Text field's border style and
  1115.                         // background color.
  1116.                         this.RecTypeDescr = "Border Style and BG Color"
  1117.                         this.ReadRecord()
  1118.                         // Extract and process border style.
  1119.                         nTemp = 0
  1120.                         If MAKEU16(this.xREC, 13) = 1
  1121.                             cStyle = "6"   // Drop Shadow
  1122.                         Else
  1123.                             For x = 1 To 8 Step 2
  1124.                                 nTemp = BitOr(nTemp, MAKEU16(this.xREC, x))
  1125.                             EndFor
  1126.                             Do Case
  1127.                                 Case (nTemp = 1) Or (nTemp = 3) Or (nTemp = 4)
  1128.                                     cStyle = "4"  // Single
  1129.                                 Case nTemp = 2
  1130.                                     cStyle = "5"  // Double
  1131.                                 Otherwise
  1132.                                     cStyle = "0"  // Default
  1133.                             EndCase
  1134.                         EndIf
  1135.                         If Type("this.CurrentObject") == "O"
  1136.                             // Assign border style to current Text template.
  1137.                             this.CurrentObject["BorderStyle"] = cStyle
  1138.                             // VdB Text.ColorNormal is for font color,
  1139.                             // not for background color. VdB report Text
  1140.                             // class does not implement background colors.
  1141.                             // So pass message to .REP file header.
  1142.                             nTemp = RGBTriple(this.xREC, 19)
  1143.                             If nTemp # HToI("FFFFFF") And this.lLogColorError
  1144.                                 this.aErrors.Add(this.oForm.oLang.iText("BkColorNotSupported"))
  1145.                                 this.lLogColorError = False
  1146.                             EndIf
  1147.                         EndIf
  1148.  
  1149.                     Case this.RecID = HToI("1018")  // Text Field Text
  1150.                         // This case specifies the text to be displayed in
  1151.                         // a Text field (ie; a text label)
  1152.                         this.RecTypeDescr = "Text Field Text"
  1153.                         this.ReadRecord()
  1154.                         cTemp = STRIPNULL(this.xREC)
  1155.                         // Drop extraneous carriage returns and line feeds from text end
  1156.                         Do While (Asc(Right(cTemp, 1)) = 10) Or;
  1157.                                     (Asc(Right(cTemp, 1)) = 13)
  1158.                             cTemp = Left(cTemp, Len(cTemp) - 1)
  1159.                         EndDo
  1160.                         oTemp = this.CurrentObject
  1161.                         // Now that we know the current Text template will not be
  1162.                         // linked to a table field, assign a name to it using
  1163.                         // 'TEXT' + next available number.
  1164.                         oTemp.xName = this.CurrentContainer.NextName("TEXT")
  1165.                         oTemp["Text"] = '"' + cTemp + '"'
  1166.                         // Set the font attributes and height for the Text template.
  1167.                         // See the class RepObjBase::SetFont method
  1168.                         oTemp.SetFont((this))
  1169.                         // If print on multiple lines
  1170.                         If this.SaveVarHeight > 0
  1171.                             oTemp["VariableHeight"] = True
  1172.                         Else
  1173.                             oTemp["Wrap"] = False
  1174.                         EndIf
  1175.  
  1176.                     Case this.RecID = HToI("1019")  // Report Title
  1177.                         // This case specifies the report title.
  1178.                         this.RecTypeDescr = "Report Title"
  1179.                         this.ReadRecord()
  1180.                         this.oReport["Title"] = '"' + STRIPNULL(this.xREC) + '"'
  1181.  
  1182.                     Case this.RecID = HToI("101A")  // Report Comments
  1183.                         // This case specifies the report comments.
  1184.                         // These comments will be streamed to the .REP file header.
  1185.                         this.RecTypeDescr = "Report Comments"
  1186.                         this.ReadRecord()
  1187.                         this.oReport.Comments = STRIPNULL(this.xREC)
  1188.  
  1189.                     Case this.RecID = HToI("101B")  // Image Object
  1190.                         // This case describes an Image object in the .RPT file.
  1191.                         this.RecTypeDescr = "Image Object"
  1192.                         this.AddToReport()
  1193.                         this.ReadRecord()
  1194.                         // Create a new Image template.
  1195.                         this.CurrentObject =;
  1196.                                         New xImage(this.CurrentContainer.NextName("IMAGE"))
  1197.                         // Extract properties and assign to Image template.
  1198.                         nTemp = MAKEU16(this.xREC, 23)
  1199.                         If nTemp # 0
  1200.                             this.CurrentObject["Left"] = nTemp
  1201.                         EndIf
  1202.                         this.CurrentObject["Width"] = MAKEU16(this.xREC, 11)
  1203.                         nTemp = MAKEU16(this.xREC, 25)
  1204.                         If nTemp # 0
  1205.                             this.CurrentObject["Top"] = nTemp
  1206.                         EndIf
  1207.                         this.CurrentObject["Height"] = MAKEU16(this.xREC, 13)
  1208.                         this.CurrentObject["Alignment"] = 0
  1209.  
  1210.                     Case this.RecID = HToI("101C")  // Image related
  1211.                         // Don't need this. Already have necessary items.
  1212.                         this.RecTypeDescr = "Image Related"
  1213.                         this.ReadRecord(True)
  1214.  
  1215.                     Case this.RecID = HToI("101D")  // Image DataSource file
  1216.                         // This case specifies the image file to be associated
  1217.                         // with an image object.
  1218.                         this.RecTypeDescr = "Image DataSource"
  1219.                         this.ReadRecord()
  1220.                         If Type("this.CurrentObject") == "O"
  1221.                             cTemp = STRIPNULL(this.xREC)
  1222.                             If Not File(cTemp)  // If file does not exist
  1223.                                 If RAt("\", cTemp) > 0
  1224.                                     cTemp = Right(cTemp, Len(cTemp) - RAt("\", cTemp))
  1225.                                 EndIf
  1226.                                 cTemp = this.oReport.DataPath + cTemp
  1227.                             EndIf
  1228.                             If Not File(cTemp)  // If file does not exist in data path
  1229.                                 If RAt("\", cTemp) > 0
  1230.                                     cTemp = Right(cTemp, Len(cTemp) - RAt("\", cTemp))
  1231.                                 EndIf
  1232.                                 cTemp = ALLTRIM(this.oForm.SourcePathField.Value) +;
  1233.                                                                                                 cTemp
  1234.                             EndIf
  1235.                             If Not File(cTemp)  // If file does not exist in .RPT path
  1236.                                 cTemp = STRIPNULL(this.xREC)  // Let developer reconcile
  1237.                                 this.aErrors.Add(this.oForm.oLang.iText("NoImageFile") +;
  1238.                                                             " - " + this.CurrentObject.xName)
  1239.                             EndIf
  1240.                             this.CurrentObject["Datasource"] = '"FILENAME ' +;
  1241.                                                                                         cTemp + '"'
  1242.                         EndIf
  1243.  
  1244.                     Case this.RecID = HToI("101E")  // Image Bits
  1245.                         // This case is an internal store of the actual image in the .RPT
  1246.                         this.RecTypeDescr = "Image Bits"
  1247.                         this.ReadRecord(True, True)
  1248.                         this.xREC = ""
  1249.  
  1250.                     Case this.RecID = HToI("1020")  // Image as OLE - Object ID
  1251.                         // This case should not be encountered because
  1252.                         // .RPT files containing OLE are screened at the beginning.
  1253.                         this.RecTypeDescr = "Image as OLE - Object ID"
  1254.                         this.ReadRecord(True)
  1255.  
  1256.                     Case this.RecID = HToI("1022")  // Page Margins
  1257.                         // This case specifies the page margins
  1258.                         this.RecTypeDescr = "Page Margins"
  1259.                         this.ReadRecord()
  1260.                         this.oPageTemplate["MarginLeft"] = MAKEU16(this.xREC, 1)
  1261.                         this.oPageTemplate["MarginRight"] = MAKEU16(this.xREC, 3)
  1262.                         this.oPageTemplate["MarginTop"] = MAKEU16(this.xREC, 5)
  1263.                         this.oPageTemplate["MarginBottom"] = MAKEU16(this.xREC, 7)
  1264.  
  1265.                     Case this.RecID = HToI("1023")  // Column Dimensions
  1266.                         // This case specifies the dimensions used to
  1267.                         // create a multi-column report (ie; labels).
  1268.                         this.RecTypeDescr = "Column Dimensions"
  1269.                         this.ReadRecord()
  1270.                         this.MultiColumn = True
  1271.                         this.ColWidth = MAKEU16(this.xREC, 1)
  1272.                         this.ColHeight = MAKEU16(this.xREC, 3)
  1273.                         this.ColGapHorz = MAKEU16(this.xREC, 5)
  1274.                         this.ColGapVert = MAKEU16(this.xREC, 7)
  1275.                         // 0 = Across/Down, otherwise Down/Across.
  1276.                         this.ColSequence = MAKEU16(this.xREC, 9)
  1277.  
  1278.                     Case this.RecID = HToI("1024")  // Line related
  1279.                         // Don't need this. Already have necessary items.
  1280.                         this.RecTypeDescr = "Line Related"
  1281.                         this.ReadRecord(True)
  1282.  
  1283.                     Case this.RecID = HToI("1025")  // Box related
  1284.                         // Don't need this. Already have necessary items.
  1285.                         this.RecTypeDescr = "Box Related"
  1286.                         this.ReadRecord(True)
  1287.  
  1288.                     Case this.RecID = HToI("1027")  // Label Descriptor
  1289.                         // This case specifies the predefined label type
  1290.                         // (ie; 5160, etc) or user-defined labels.
  1291.                         this.RecTypeDescr = "Label Descriptor"
  1292.                         this.ReadRecord()
  1293.                         cTemp = Left(this.xREC, this.RecLen - 1)
  1294.                         If (Len(cTemp) = 0) Or (At(Chr(0), cTemp) = 0)
  1295.                             cTemp = "User Defined Label" + Chr(0)
  1296.                         EndIf
  1297.                         this.oReport.LabelType = Left(cTemp, At(Chr(0), cTemp) - 1)
  1298.                         this.oReport.LabelStyle = Right(cTemp, Len(cTemp) -;
  1299.                                                                     At(Chr(0), cTemp))
  1300.  
  1301.                     Case this.RecID = HToI("1028")  // Line Object
  1302.                         // This case adds a Line to the report.
  1303.                         this.RecTypeDescr = "Line Object"
  1304.                         this.AddToReport()
  1305.                         this.ReadRecord()
  1306.                         // Create a Line template.
  1307.                         oTemp = New xLine("")
  1308.                         // Extract and process the pen style.
  1309.                         nTemp = MAKEU16(this.xREC, 5)
  1310.                         Do Case
  1311.                             Case nTemp = 1
  1312.                                 oTemp["Pen"] = 0
  1313.                             Case nTemp = 3
  1314.                                 oTemp["Pen"] = 1
  1315.                             Case nTemp = 4
  1316.                                 oTemp["Pen"] = 2
  1317.                             Otherwise
  1318.                                 this.aErrors.Add(this.oForm.oLang.iText("PenTypeNotSupported"))
  1319.                         EndCase
  1320.                         // Extract and process remaining properties
  1321.                         oTemp["Width"] = MAKEU16(this.xREC, 7)
  1322.                         cTemp = RGBTRIPLE(this.xREC, 9)
  1323.                         // Use JavaScript color tag if available or hexadecimal if not
  1324.                         oTemp["ColorNormal"] = '"' + IIf(this.aaColors.IsKey(cTemp),;
  1325.                                                                     this.aaColors[cTemp],;
  1326.                                                                     '0x' + cTemp) + '"'
  1327.                         oTemp.TopBandIndex = MAKEU16(this.xREC, 13) + 1
  1328.                         oTemp.TopLineIndex = MAKEU16(this.xREC, 15) + 1
  1329.                         oTemp["Left"] = MAKEU16(this.xREC, 17)
  1330.                         oTemp["Top"] = MAKEU16(this.xREC, 19)
  1331.  
  1332.                         oTemp.BotBandIndex = MAKEU16(this.xREC, 21) + 1
  1333.                         oTemp.BotLineIndex = MAKEU16(this.xREC, 23) + 1
  1334.                         oTemp["Right"] = MAKEU16(this.xREC, 25)
  1335.                         oTemp["Bottom"] = MAKEU16(this.xREC, 27)
  1336.                         // Save a reference to the Line template. It will be used
  1337.                         // later to assign the Line to the correct container after
  1338.                         // the report band heights are justified.
  1339.                         this.aLines.Add(oTemp)
  1340.  
  1341.                     Case this.RecID = HToI("1029")  // Box Object (shape)
  1342.                         // This case adds a box object (Shape) to the report.
  1343.                         this.RecTypeDescr = "Box Object (shape)"
  1344.                         this.AddToReport()
  1345.                         this.ReadRecord()
  1346.                         // Create a Shape template.
  1347.                         oTemp = New xShape("")
  1348.                         // Extract and process the pen style.
  1349.                         nTemp = MAKEU16(this.xREC, 5)
  1350.                         Do Case
  1351.                             Case nTemp = 1
  1352.                                 oTemp["PenStyle"] = 0
  1353.                             Case nTemp = 3
  1354.                                 oTemp["PenStyle"] = 1
  1355.                             Case nTemp = 4
  1356.                                 oTemp["PenStyle"] = 2
  1357.                             Otherwise
  1358.                                 this.aErrors.Add(this.oForm.oLang.iText("PenTypeNotSupported"))
  1359.                         EndCase
  1360.                         // Extract and process remaining properties
  1361.                         oTemp["PenWidth"] = MAKEU16(this.xREC, 7)
  1362.                         cTemp = RGBTRIPLE(this.xREC, 9)
  1363.                         lTemp = RGBTRIPLE(this.xREC, 39)
  1364.                         If Not (cTemp == "000000" And lTemp == "000000")
  1365.                             // Use JavaScript color tag if available or hexadecimal if not
  1366.                             oTemp["ColorNormal"] = '"' + IIf(this.aaColors.IsKey(cTemp),;
  1367.                                                                         this.aaColors[cTemp],;
  1368.                                                                         '0x' + cTemp) + "/" +;
  1369.                                                                     IIf(this.aaColors.IsKey(lTemp),;
  1370.                                                                         this.aaColors[lTemp],;
  1371.                                                                         '0x' + lTemp) + '"'
  1372.                         EndIf
  1373.                         oTemp.TopBandIndex = MAKEU16(this.xREC, 45) + 1
  1374.                         oTemp.TopLineIndex = MAKEU16(this.xREC, 47) + 1
  1375.                         oTemp["Left"] = MAKEU16(this.xREC, 49)
  1376.                         oTemp["Top"] = MAKEU16(this.xREC, 51)
  1377.  
  1378.                         oTemp.BotBandIndex = MAKEU16(this.xREC, 53) + 1
  1379.                         oTemp.BotLineIndex = MAKEU16(this.xREC, 55) + 1
  1380.                         oTemp["Width"] = MAKEU16(this.xREC, 57) - oTemp["Left"]
  1381.                         oTemp["Height"] = MAKEU16(this.xREC, 59)
  1382.                         // Save a reference to the Shape template. It will be used
  1383.                         // later to assign the Shape to the correct container after
  1384.                         // the report band heights are justified.
  1385.                         this.aShapes.Add(oTemp)
  1386.  
  1387.                     Case this.RecID = HToI("102A")  // Item Color
  1388.                         // This case is used to specify the color used for the current
  1389.                         // font, or the current line, or the current shape, etc.
  1390.                         this.RecTypeDescr = "Item Color"
  1391.                         this.ReadRecord()
  1392.                         nTemp = MAKEU24(this.xREC, 1)
  1393.                         cTemp = RGBTRIPLE(this.xREC, 1)
  1394.                         If this.ReadingLine
  1395.                             If this.CurColor # nTemp And this.CurColor # HTML_DEFCOLOR
  1396.                                 this.CurrentLine.HTMLText += '</font>'
  1397.                                 this.CurColor = HTML_DEFCOLOR
  1398.                             EndIf
  1399.                             If this.CurColor = HTML_DEFCOLOR And nTemp # this.CurColor
  1400.                             // Use JavaScript color tag if available or hexadecimal if not
  1401.                                 this.CurrentLine.HTMLText += '<font color="' +;
  1402.                                                                 IIf(this.aaColors.IsKey(cTemp),;
  1403.                                                                             this.aaColors[cTemp],;
  1404.                                                                             "#" + cTemp) + '">'
  1405.                             EndIf
  1406.                             this.CurColor = nTemp
  1407.                         ElseIf Type("this.CurrentObject") == "O"
  1408.                             // Use JavaScript color tag if available or hexadecimal if not
  1409.                             this.CurrentObject["ColorNormal"] = '"' +;
  1410.                                                     IIf(this.aaColors.IsKey(cTemp),;
  1411.                                                             this.aaColors[cTemp],;
  1412.                                                             '0x' + cTemp) + '"'
  1413.                         EndIf
  1414.  
  1415.                     Case this.RecID = HToI("102B")  // Image as OLE - Formatting
  1416.                         // This case should not be encountered because
  1417.                         // .RPT files containing OLE are screened at the beginning.
  1418.                         this.RecTypeDescr = "Image as OLE - Formatting"
  1419.                         this.ReadRecord(True)
  1420.  
  1421.                     Case this.RecID = HToI("2003")  // ?? and Database|Verify Before Printing
  1422.                         // This case contains no significant information
  1423.                         this.RecTypeDescr = "?? and Database|Verify Before Printing"
  1424.                         this.ReadRecord(True)
  1425.  
  1426.                     Case this.RecID = HToI("2004")  // Data File
  1427.                         // If the .RPT is single-table based, this is the table filename.
  1428.                         // If the .RPT is .QBE based, this is the .QBE filename.
  1429.                         this.RecTypeDescr = "Data File"
  1430.                         this.ReadRecord()
  1431.                         this.oReport.DataFile = STRIPNULL(this.xREC)
  1432.  
  1433.                     Case this.RecID = HToI("2005")  // Data Path
  1434.                         // This is the data path used with 2004
  1435.                         this.RecTypeDescr = "Data Path"
  1436.                         this.ReadRecord()
  1437.                         cTemp = ""
  1438.                         If this.RecLen > 1
  1439.                             cTemp = STRIPNULL(this.xREC)
  1440.                         ElseIf At("\", this.oForm.SourcePathField.Value) > 0
  1441.                             cTemp = this.oForm.SourcePathField.Value
  1442.                             cTemp = Left(cTemp, RAt("\", cTemp))
  1443.                         EndIf
  1444.                         this.oReport.DataPath = cTemp
  1445.                         this.aQBEFiles.cDefaultPath = cTemp
  1446.                         this.oReport.DataFile = cTemp + this.oReport.DataFile
  1447.                         If Upper(Right(this.oReport.DataFile, 4)) == ".QBE" And;
  1448.                                                                     File(this.oReport.DataFile)
  1449.                             this.aQBEFiles.Parse(this.oReport.DataFile)
  1450.                         EndIf
  1451.  
  1452.                     Case this.RecID = HToI("2006")  // DLL File
  1453.                         // This is the CRW .DLL file used to render the report.
  1454.                         // Currently not used in report conversions.
  1455.                         this.RecTypeDescr = "DLL File"
  1456.                         this.ReadRecord()
  1457.                         this.oReport.DLLFile = Left(this.xREC, this.RecLen - 1)
  1458.  
  1459.                     Case this.RecID = HToI("2007")  // Table Field Count
  1460.                         // This is a total table field count for all tables in .RPT file.
  1461.                         // This is unreliable and is not used for verification during
  1462.                         // conversion.
  1463.                         this.RecTypeDescr = "Table Field Count"
  1464.                         this.ReadRecord()
  1465.  
  1466.                     Case this.RecID = HToI("2008")  // Table Field Name
  1467.                         // This is a table name and table field name in
  1468.                         // TABLE->FIELD format.
  1469.                         this.RecTypeDescr = "Table Field Name"
  1470.                         this.ReadRecord()
  1471.                         this.xREC = STRIPNULL(this.xREC)
  1472.                         cTemp = Left(this.xREC, At("->", this.xREC) - 1)
  1473.                         this.FieldName = Right(this.xREC,;
  1474.                                                 (Len(this.xREC) - At("->", this.xREC)) - 1)
  1475.                         If Not this.CurrentTable == cTemp Or;
  1476.                                         this.oReport.aTables[this.oReport.aTables.Size].IsKey(this.FieldName)
  1477.                             this.oReport.aTables.Add(New DataTable())
  1478.                             this.oReport.aTables[this.oReport.aTables.Size].Alias =;
  1479.                                                                                     cTemp
  1480.                             this.CurrentTable = cTemp
  1481.                         EndIf
  1482.  
  1483.                     Case this.RecID = HToI("2009")  // Table Field Data Type
  1484.                         // This is the table field data type for 2008.
  1485.                         // The data type is currently not used for report conversions.
  1486.                         this.RecTypeDescr = "Table Field Data Type"
  1487.                         this.ReadRecord()
  1488.                         nTemp = MAKE8(this.xREC, 1)
  1489.                         Do Case
  1490.                             Case nTemp = 6 Or nTemp = 4 Or nTemp = 2 Or nTemp = 7
  1491.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1492.                                                             [this.FieldName] = "N"
  1493.                             Case nTemp = 8
  1494.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1495.                                                             [this.FieldName] = "L"
  1496.                             Case nTemp = 9
  1497.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1498.                                                             [this.FieldName] = "D"
  1499.                             Case nTemp = 11
  1500.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1501.                                                             [this.FieldName] = "C"
  1502.                             Case nTemp = 13
  1503.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1504.                                                             [this.FieldName] = "M"
  1505.                             Case nTemp = 14
  1506.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1507.                                                             [this.FieldName] = "B"
  1508.                             Otherwise
  1509.                                 this.oReport.aTables[this.oReport.aTables.Size];
  1510.                                                             [this.FieldName] = "U"
  1511.                         EndCase
  1512.  
  1513.                     Case this.RecID = HToI("2011")  // Database Name
  1514.                         // This is a database name field.
  1515.                         this.RecTypeDescr = "Database Name"
  1516.                         this.ReadRecord()
  1517.                         this.oReport.Database = STRIPNULL(this.xREC)
  1518.  
  1519.                     Otherwise                       // Unknown/unneeded record type
  1520.                         this.RecTypeDescr = "Unknown/unnecessary Record Type"
  1521.                         this.ReadRecord(Not this.StreamAll)
  1522.                         If Not this.StreamAll And this.Debug
  1523.                             this.CurrentContainer.Objects.Add (New RecordStream(;
  1524.                                     this.nFPos, this.RecID, this.RecTypeDescr, this.xREC))
  1525.                         EndIf
  1526.  
  1527.                 EndCase
  1528.                 If this.StreamAll And this.RecID # HToI("101E")  // Image bits
  1529.                     this.CurrentContainer.Objects.Add(New RecordStream(this.nFPos,;
  1530.                                                 this.RecID, this.RecTypeDescr, this.xREC))
  1531.                 EndIf
  1532.                 this.UpdateProgress((this.nFPos / this.nFSize) * 100)
  1533.             EndDo
  1534.             // Ensure that the last object constructed is added to the array cluster
  1535.             this.AddToReport()
  1536.             this.ReadingRptFooter = False
  1537.  
  1538.             // Add the StreamFrame template to the .REP array cluster
  1539.             // as a child object of the PageTemplate.
  1540.             this.CurrentContainer = this.oPageTemplate
  1541.             this.CurrentObject = this.oStreamFrame
  1542.             this.AddToReport()
  1543.  
  1544.             If this.nFPos # this.nFSize
  1545.                 this.oError.LineNo = LineNo() - 1
  1546.                 this.oError.Filename = Program()
  1547.                 this.oError.Code = 10003
  1548.                 Throw this.oError
  1549.             EndIf
  1550.  
  1551.             // Update SQL statements with ORDER BY...
  1552.             For nTemp = 1 To this.oReport.aTables.Size
  1553.                 If this.oReport.aTables[nTemp].aOrders.Size > 0 Or;
  1554.                                         this.oReport.aTables[nTemp].aGroups.Size > 0
  1555.                     For lTemp = 1 To this.aQueries.Size
  1556.                         If this.aQueries[lTemp].TableName ==;
  1557.                                                 this.oReport.aTables[nTemp].TableName And;
  1558.                                                             Not this.aQueries[lTemp].Indexed
  1559.                             cTemp = Left(this.aQueries[lTemp]["SQL"],;
  1560.                                                 Len(this.aQueries[lTemp]["SQL"]) - 1)
  1561.                             For oTemp = 1 To this.oReport.aTables[nTemp].aOrders.Size;
  1562.                                                                                                 Step 2
  1563.                         // check for expressions in Order By fields
  1564.                         cOrderby = this.oReport.aTables[nTemp].aOrders[oTemp]
  1565.                         if at('(',cOrderBy) > 0
  1566.                            cOrderBy = substr(cOrderby,at('(',cOrderBy)+1)
  1567.                         endif
  1568.                         if at(')',cOrderBy) > 0
  1569.                            cOrderBy = substr(cOrderBy, 1,at(')',cOrderBy) -1)
  1570.                         endif
  1571.  
  1572.                          cTemp += IIf(oTemp = 1, " ORDER BY ", ", ") +cOrderBy+" "+;
  1573.                                              this.oReport.aTables[nTemp].aOrders[oTemp + 1]                
  1574.                             EndFor
  1575.                             this.aQueries[lTemp]["SQL"] = cTemp + "'"
  1576.                             Exit
  1577.                         EndIf
  1578.                     EndFor
  1579.                 EndIf
  1580.             EndFor
  1581.             If Len(this.cStreamQuery) = 0
  1582.                 this.cStreamQuery = this.aQueries[1].xName
  1583.             EndIf
  1584.  
  1585.             // Order the CRW print bands in the proper sequence
  1586.             aTemp = New Array()
  1587.             For nTemp = 2000 To 7000 Step 1000
  1588.                 For nTop = 1 To this.aCRWBands.Size
  1589.                     If this.aCRWBands[nTop].ID = nTemp
  1590.                         aTemp.Add(this.aCRWBands[nTop])
  1591.                     EndIf
  1592.                 EndFor
  1593.             EndFor
  1594.             this.aCRWBands = aTemp
  1595.  
  1596.             // Up to this point, many positions/sizes were relative
  1597.             // coming from the .RPT file. We now need to justify the
  1598.             // position and/or size of various report objects.
  1599.             //
  1600.             // Justify the Top/Height values for the report bands and objects.
  1601.             nBandTop = 0
  1602.             nHorz = Int(this.oPageTemplate["Width"] -;
  1603.                                                 this.oPageTemplate["MarginLeft"] -;
  1604.                                                 this.oPageTemplate["MarginRight"])
  1605.  
  1606.             For nTemp = 1 To this.aCRWBands.Size
  1607.                 aLines = this.aCRWBands[nTemp]
  1608.                 aLines.Top = nBandTop
  1609.                 aLines.Height = 0
  1610.                 For lTemp = 1 To aLines.Size
  1611.                     aLines[lTemp].Top = aLines.Height
  1612.                     aLines[lTemp].PositionObjectsToBaseline(nHorz)
  1613.                     If this.MultiColumn And;
  1614.                                             this.aCRWBands[nTemp].ID = CRWBAND_RPTDETAIL
  1615.                         aLines[lTemp].SetSuppressIfBlank()
  1616.                     EndIf
  1617.                     aLines.Height += aLines[lTemp].Height
  1618.                 EndFor
  1619.                 nBandTop += aLines.Height
  1620.                 If aLines.ID = CRWBAND_RPTDETAIL Or;
  1621.                             aLines.ID = CRWBAND_GRPHEADER Or;
  1622.                             aLines.ID = CRWBAND_GRPFOOTER Or;
  1623.                             aLines.ID = CRWBAND_GRNDTOTAL
  1624.                     aLines.Container["Height"] = aLines.Height
  1625.                 EndIf
  1626.             EndFor
  1627.             this.oReport.aStreamFrames.Add(this.oStreamFrame)
  1628.  
  1629.             // Now that the above is accomplished, the .REP PageTemplate,
  1630.             // StreamFrame(s), etc need to be sized and positioned.
  1631.             If this.MultiColumn                    // Label or user-defined label report
  1632.                 // Setup the detail band
  1633.                 this.oDetailBand["Expandable"] = False
  1634.                 this.oDetailBand["BeginNewFrame"] = True
  1635.                 this.oDetailBand["Height"] = this.ColHeight
  1636.                 this.oStreamFrame["Height"] = this.ColHeight
  1637.                 this.oStreamFrame["Width"] = this.ColWidth
  1638.                 AcrossCount = Int((this.oPageTemplate["Width"] -;
  1639.                                                 this.oPageTemplate["MarginLeft"] -;
  1640.                                                 this.oPageTemplate["MarginRight"] -;
  1641.                                                 this.ColWidth) /;
  1642.                                                 (this.ColWidth + this.ColGapHorz))
  1643.                 DownCount = Int((this.oPageTemplate["Height"] -;
  1644.                                                 this.oPageTemplate["MarginTop"] -;
  1645.                                                 this.oPageTemplate["MarginBottom"] -;
  1646.                                                 this.ColHeight) /;
  1647.                                                 (this.ColHeight + this.ColGapVert))
  1648.                 this.CurrentContainer = this.oPageTemplate
  1649.                 nTop = 0
  1650.                 nLeft = 0
  1651.                 If this.ColSequence = 0                // Across/Down
  1652.                     For nVert = 1 To DownCount + 1
  1653.                         For nHorz = 1 To AcrossCount + 1
  1654.                             If nVert # 1 Or nHorz # 1  // If not the first StreamFrame
  1655.                                 // Create multiple StreamFrames - 1 for each label on sheet
  1656.                                 this.CurrentObject = New xStreamFrame(;
  1657.                                                 this.oPageTemplate.NextName("STREAMFRAME"))
  1658.                                 this.oReport.aStreamFrames.Add(this.CurrentObject)
  1659.                                 this.CurrentObject["Metric"] = 1
  1660.                                 If nLeft # 0
  1661.                                     this.CurrentObject["Left"] = nLeft
  1662.                                 EndIf
  1663.                                 If nTop # 0
  1664.                                     this.CurrentObject["Top"] = nTop
  1665.                                 EndIf
  1666.                                 this.CurrentObject["Width"] = this.ColWidth
  1667.                                 this.CurrentObject["Height"] = this.ColHeight
  1668.                                 this.AddToReport()
  1669.                             EndIf
  1670.                             nLeft += this.ColWidth + this.ColGapHorz
  1671.                         EndFor
  1672.                         nLeft = 0
  1673.                         nTop += this.ColHeight + this.ColGapVert
  1674.                     EndFor
  1675.                 Else                                        // Down/Across
  1676.                     For nHorz = 1 To AcrossCount + 1
  1677.                         For nVert = 1 To DownCount + 1
  1678.                             If nVert # 1 Or nHorz # 1  // If not the first StreamFrame
  1679.                                 // Create multiple StreamFrames - 1 for each label on sheet
  1680.                                 this.CurrentObject = New xStreamFrame(;
  1681.                                                 this.oPageTemplate.NextName("STREAMFRAME"))
  1682.                                 this.oReport.aStreamFrames.Add(this.CurrentObject)
  1683.                                 this.CurrentObject["Metric"] = 1
  1684.                                 If nLeft # 0
  1685.                                     this.CurrentObject["Left"] = nLeft
  1686.                                 EndIf
  1687.                                 If nTop # 0
  1688.                                     this.CurrentObject["Top"] = nTop
  1689.                                 EndIf
  1690.                                 this.CurrentObject["Width"] = this.ColWidth
  1691.                                 this.CurrentObject["Height"] = this.ColHeight
  1692.                                 this.AddToReport()
  1693.                             EndIf
  1694.                             nTop += this.ColHeight + this.ColGapVert
  1695.                         EndFor
  1696.                         nTop = 0
  1697.                         nLeft += this.ColWidth + this.ColGapHorz
  1698.                     EndFor
  1699.                 EndIf
  1700.             Else                                            // Non-label report
  1701.                 If this.aCRWBands[1].Height # 0
  1702.                     this.oStreamFrame["Top"] = this.aCRWBands[1].Height
  1703.                 EndIf
  1704.                 this.oStreamFrame["Height"] = this.oPageTemplate["Height"] -;
  1705.                                                 this.oPageTemplate["MarginTop"] -;
  1706.                                                 this.oPageTemplate["MarginBottom"] -;
  1707.                                                 this.aCRWBands[1].Height -;
  1708.                                                 this.aCRWBands[this.aCRWBands.Size].Height
  1709.                 this.aCRWBands[this.aCRWBands.Size].Top = this.oStreamFrame["Top"] +;
  1710.                                                                     this.oStreamFrame["Height"]
  1711.                 this.oStreamFrame["Width"] = this.oPageTemplate["Width"] -;
  1712.                                                 this.oPageTemplate["MarginLeft"] -;
  1713.                                                 this.oPageTemplate["MarginRight"]
  1714.                 For nTemp = 1 To this.oPageTemplate.Objects.Size
  1715.                     If this.oPageTemplate.Objects[nTemp].RptFooterObject And;
  1716.                             Not this.oPageTemplate.Objects[nTemp].xClassName == "BLANK"
  1717.                         If this.oPageTemplate.Objects[nTemp].IsKey("Top")
  1718.                             this.oPageTemplate.Objects[nTemp]["Top"] +=;
  1719.                                                                     this.oStreamFrame["Top"] +;
  1720.                                                                     this.oStreamFrame["Height"]
  1721.                         Else
  1722.                             this.oPageTemplate.Objects[nTemp]["Top"] =;
  1723.                                                                     this.oStreamFrame["Top"] +;
  1724.                                                                     this.oStreamFrame["Height"]
  1725.                         EndIf
  1726.                     EndIf
  1727.                 EndFor
  1728.             EndIf
  1729.  
  1730.             // Justify Shapes to their respective bands
  1731.             For nTemp = 1 To this.aShapes.Size
  1732.                 aTemp = this.aCRWBands[this.aShapes[nTemp].TopBandIndex]
  1733.                 this.aShapes[nTemp]["Top"] +=;
  1734.                                                 aTemp[this.aShapes[nTemp].TopLineIndex].Top
  1735.                 aTemp = this.aCRWBands[this.aShapes[nTemp].BotBandIndex]
  1736.                 this.aShapes[nTemp]["Height"] +=;
  1737.                                                 aTemp[this.aShapes[nTemp].BotLineIndex].Top
  1738.                 If this.aShapes[nTemp].TopBandIndex #;
  1739.                                                             this.aShapes[nTemp].BotBandIndex
  1740.                     this.aShapes[nTemp]["Height"] +=;
  1741.                                                     (aTemp.Top - this.aShapes[nTemp]["Top"])
  1742.                 EndIf
  1743.                 If this.aShapes[nTemp].TopBandIndex = this.aCRWBands.Size
  1744.                     this.aShapes[nTemp]["Top"] += aTemp.Top
  1745.                 EndIf
  1746.                 // Now add the Shape to the .REP array cluster
  1747.                 this.CurrentContainer =;
  1748.                             this.aCRWBands[this.aShapes[nTemp].TopBandIndex].Container
  1749.                 this.CurrentObject = this.aShapes[nTemp]
  1750.                 this.CurrentObject.xName = this.CurrentContainer.NextName("SHAPE")
  1751.                 this.AddToReport()
  1752.             EndFor
  1753.  
  1754.             // Justify Lines to their respective bands or to the PageTemplate
  1755.             For nTemp = 1 To this.aLines.Size
  1756.                 aLinesTop = this.aCRWBands[this.aLines[nTemp].TopBandIndex]
  1757.                 aLinesBot = this.aCRWBands[this.aLines[nTemp].BotBandIndex]
  1758.                 If this.aLines[nTemp]["Top"] > 32766
  1759.                     this.aLines[nTemp]["Top"] = aLinesTop.Height - 1
  1760.                 Else
  1761.                     // Compute line top relative to the top of the CRW band line
  1762.                     // containing the top of the line
  1763.                     this.aLines[nTemp]["Top"] +=;
  1764.                                             aLinesTop[this.aLines[nTemp].TopLineIndex].Top
  1765.                 EndIf
  1766.                 // If the top of the line is contained in the CRW report footer...
  1767.                 If this.aLines[nTemp].TopBandIndex = this.aCRWBands.Size
  1768.                     // Compute the top of the line relative to the top of the
  1769.                     // CRW report footer
  1770.                     this.aLines[nTemp]["Top"] += aLinesTop.Top
  1771.                 EndIf
  1772.                 If this.aLines[nTemp]["Bottom"] > 32766
  1773.                     this.aLines[nTemp]["Bottom"] = aLinesBot.Height - 1
  1774.                 Else
  1775.                     // Compute line bottom relative to the top of the CRW band line
  1776.                     // containing the bottom of the line
  1777.                     this.aLines[nTemp]["Bottom"] +=;
  1778.                                             aLinesBot[this.aLines[nTemp].BotLineIndex].Top
  1779.                 EndIf
  1780.                 If this.aLines[nTemp].BotBandIndex = this.aCRWBands.Size Or;
  1781.                                                         this.aLines[nTemp].BotBandIndex #;
  1782.                                                         this.aLines[nTemp].TopBandIndex
  1783.                     // ...Then compute the bottom of the line relative to the
  1784.                     // top of the CRW band which contains the bottom of the line
  1785.                     this.aLines[nTemp]["Bottom"] += aLinesBot.Top
  1786.                 EndIf
  1787.                 If this.aLines[nTemp]["Left"] > this.oStreamFrame["Width"] - 1
  1788.                     this.aLines[nTemp]["Left"] = this.oStreamFrame["Width"] - 1
  1789.                 EndIf
  1790.                 If this.aLines[nTemp]["Right"] > this.oStreamFrame["Width"] - 1
  1791.                     this.aLines[nTemp]["Right"] = this.oStreamFrame["Width"] - 1
  1792.                 EndIf
  1793.                 nTop =  this.oPageTemplate["Height"] -;
  1794.                                                 this.oPageTemplate["MarginTop"] -;
  1795.                                                 this.oPageTemplate["MarginBottom"] - 1
  1796.                 If this.aLines[nTemp]["Top"] > nTop
  1797.                     this.aLines[nTemp]["Top"] = nTop
  1798.                 EndIf
  1799.                 If this.aLines[nTemp]["Bottom"] > nTop
  1800.                     this.aLines[nTemp]["Bottom"] = nTop
  1801.                 EndIf
  1802.                 // Now add the Line to the .REP array cluster
  1803.                 this.CurrentContainer =;
  1804.                             this.aCRWBands[this.aLines[nTemp].TopBandIndex].Container
  1805.                 this.CurrentObject = this.aLines[nTemp]
  1806.                 this.CurrentObject.xName = this.CurrentContainer.NextName("LINE")
  1807.                 this.AddToReport()
  1808.             EndFor
  1809.  
  1810.         Catch(RBException x)  // Program-detected errors are caught here
  1811.             this.oError.OnError(x)
  1812.             this.CriticalError = True
  1813.         Catch(Exception x)    // VdB-detected errors are caught here
  1814.             this.oError.OnError(x)
  1815.             this.CriticalError = True
  1816.         Finally               // Release device context and close file handle
  1817.           BL_lReleaseDC(_app.FrameWin.hWND, this.hDC)
  1818.             fClose(this.hInFile)
  1819.             this.hInFile = 0
  1820.         EndTry
  1821.         RETURN Not this.CriticalError  // True if no error, False if error
  1822.  
  1823.     FUNCTION FieldType(cFldRef)
  1824.         LOCAL cAlias, cField, nTable, nField, cTemp
  1825.  
  1826.         cAlias = Left(cFldRef, At("->", cFldRef) - 1)
  1827.         cField = SubStr(cFldRef, At("->", cFldRef) + 2)
  1828.         For nTable = 1 To this.oReport.aTables.Size
  1829.             If this.oReport.aTables[nTable].Alias == cAlias
  1830.                 RETURN IIf(this.oReport.aTables[nTable].IsKey(cField),;
  1831.                                                 this.oReport.aTables[nTable][cField], "U")
  1832.             EndIf
  1833.         EndFor
  1834.         RETURN "U"
  1835.  
  1836.     FUNCTION ConvertFormula(c)
  1837.         // Convert field references in FIELD format to TABLE->FIELD format
  1838.         LOCAL nInd, cTemp, nStart, cResult, nHits
  1839.  
  1840.         cResult = c
  1841.         For nInd = this.oReport.aTables.Size To 1 Step -1
  1842.             cTemp = this.oReport.aTables[nInd].FirstKey
  1843.             Do While Not Empty(cTemp)
  1844.                 nHits = 1
  1845.                 nStart = At(cTemp, Upper(cResult), nHits)
  1846.                 Do While nStart > 0
  1847.                     If SubStr(cResult, nStart - 2, 2) # "->" And;
  1848.                                         (SubStr(cResult, nStart - 1, 1) $;
  1849.                                                                 Chr(9) + " ,+-*/$=#<>^'(" Or;
  1850.                                         nStart = 1) And;
  1851.                                         SubStr(cResult, nStart + Len(cTemp), 2) # "->" And;
  1852.                                         (SubStr(cResult, nStart + Len(cTemp), 1) $;
  1853.                                                                 Chr(9) + " ,+-*/$=#<>^')" Or;
  1854.                                         nStart + (Len(cTemp) - 1) = Len(cResult)) And;
  1855.                                         Not this.IsInString(cTemp, Upper(cResult), nHits)
  1856.                         cResult = Stuff(cResult, nStart, 0,;
  1857.                                                     this.oReport.aTables[nInd].Alias + "->")
  1858.                     EndIf
  1859.                     nStart = At(cTemp, Upper(cResult), ++nHits)
  1860.                 EndDo
  1861.                 cTemp = this.oReport.aTables[nInd].NextKey(cTemp)
  1862.             EndDo
  1863.         EndFor
  1864.         RETURN cResult
  1865.  
  1866.     FUNCTION IsInString(cSub, cString, nCnt)
  1867.         LOCAL lDQuote, lSQuote, lBracket, nEnd, nInd, cChar
  1868.  
  1869.         lDQuote = False
  1870.         lSQuote = False
  1871.         lBracket = False
  1872.         nEnd = At(cSub, cString, nCnt) - 1
  1873.         For nInd = 1 To nEnd
  1874.             cChar = SubStr(cString, nInd, 1)
  1875.             If cChar == "[" And Not lSQuote And Not lDQuote
  1876.                 lBracket = True
  1877.             ElseIf cChar == "]" And lBracket
  1878.                 lBracket = False
  1879.             ElseIf cChar == '"' And Not lSQuote And Not lBracket
  1880.                 lDQuote = Not lDQuote
  1881.             ElseIf cChar == "'" And Not lDQuote And Not lBracket
  1882.                 lSQuote = Not lSQuote
  1883.             EndIf
  1884.         EndFor
  1885.         RETURN lDQuote Or lSQuote Or lBracket
  1886.  
  1887.     FUNCTION ConvertField(c)
  1888.         // Convert field references in TABLE->FIELD format to
  1889.         // QueryName.RowSet.Fields["FIELD"].Value syntax.
  1890.         LOCAL nTemp, nInd, cTemp, cTable, cField, nStart, nEnd, cResult
  1891.  
  1892.         cResult = c
  1893.         Do While True
  1894.             nTemp = At("->", cResult)
  1895.             If nTemp = 0
  1896.                 Exit
  1897.             EndIf
  1898.             cTable = ""
  1899.             For nInd = nTemp - 1 To 1 Step -1
  1900.                 If SubStr(cResult, nInd, 1) $ '(",+-*/<>=[]'
  1901.                     Exit
  1902.                 EndIf
  1903.                 cTable = SubStr(cResult, nInd, 1) + cTable
  1904.             EndFor
  1905.             cTable = ALLTRIM(cTable) + "1"
  1906.             nStart = nInd + 1
  1907.             cField = ""
  1908.             For nInd = nTemp + 2 To Len(cResult)
  1909.                 If SubStr(cResult, nInd, 1) $ ')",+-*/<>=[]'
  1910.                     Exit
  1911.                 EndIf
  1912.                 cField += SubStr(cResult, nInd, 1)
  1913.             EndFor
  1914.             cField = ALLTRIM(cField)
  1915.             nEnd = nInd
  1916.             cResult = Stuff(cResult, nStart, nEnd - nStart,;
  1917.                                     'this.Form.' + cTable + '.RowSet.Fields["' +;
  1918.                                     cField + '"].Value ')
  1919.         EndDo
  1920.         RETURN "{|| " + cResult + "}"
  1921.  
  1922.     PROCEDURE AddToReport
  1923.         // Adds the current object to the .REP array cluster
  1924.  
  1925.         If Type("this.CurrentObject") $ "O|A"
  1926.             If    this.CurrentObject.VdBReportObject
  1927.                 this.CurrentObject.RptFooterObject = this.ReadingRptFooter
  1928.                 this.CurrentContainer.Objects.Add(this.CurrentObject)
  1929.                 If this.CurrentObject.xClassName # "BLANK"
  1930.                     ++ this.ObjectCount
  1931.                 Else
  1932.                     this.CurrentObject["Height"] = this.CurrentLine.Height
  1933.                 EndIf
  1934.                 If this.CurrentObject.xClassName == "TEXT" Or;
  1935.                             this.CurrentObject.xClassName == "BLANK"
  1936.                     this.ObjectsLine.Add(this.CurrentObject)
  1937.                 EndIf
  1938.             EndIf
  1939.         EndIf
  1940.         this.CurrentObject = Null
  1941.  
  1942.     PROCEDURE ReadRecord(lSkip, lForce)
  1943.         // Reads next record in .RPT file.
  1944.         // If lSkip = True, moves file pointer without actually reading.
  1945.         // If lForce = True, forces file pointer movement without reading
  1946.         // (necessary when encountering stored image bits and this.StreamAll = True)
  1947.  
  1948.         this.nFPos += this.RecLen
  1949.         If lSkip And (Not this.StreamAll Or lForce)
  1950.             fSeek(this.hInFile, this.RecLen, 1)
  1951.             RETURN
  1952.         EndIf
  1953.         this.xREC = fRead(this.hInFile, this.RecLen)
  1954.         If Len(this.xREC) = this.RecLen
  1955.             RETURN
  1956.         EndIf
  1957.         this.oError.LineNo = LineNo - 1
  1958.         this.oError.Filename = Program()
  1959.         this.oError.Code = 10004
  1960.         Throw this.oError
  1961.  
  1962.     FUNCTION SkipNulls
  1963.         // Reads through garbage nulls which are sometimes encountered
  1964.         // in .RPT file.
  1965.         LOCAL xTemp
  1966.  
  1967.         fSeek(this.hInFile, -4, 1)
  1968.         this.nFPos -= 4
  1969.         Do
  1970.             xTemp = fRead(this.hInFile, 1)
  1971.             ++ this.nFPos
  1972.         Until xTemp # Chr(0)
  1973.         fSeek(this.hInFile, -1, 1)
  1974.         -- this.nFPos
  1975.  
  1976.     FUNCTION GetItemSize(cText)
  1977.         // Computes cText height and width based on length of text
  1978.         // and current font attributes.
  1979.         LOCAL hOrgFont, hFont, nTemp
  1980.         PRIVATE xSIZE, hDC
  1981.  
  1982.         hFont = BL_CreateFont(;
  1983.                 Int(((this.FontSize *;
  1984.                     BL_GetDeviceCaps(this.hDC, LOGPIXELSY)) / 72) * 17.7),;// Height
  1985.                     0,;                                    // Width (Defaulted based on height)
  1986.                     0,;                                    // Incline
  1987.                     0,;                                    // Rotation
  1988.                     this.FontBold,;                    // Font weight
  1989.                     this.FontItalic,;                    // Italic
  1990.                     this.FontUnderline,;                // Underline
  1991.                     this.FontStrikeout,;                // Strikeout
  1992.                     ANSI_CHARSET,;                        // Character set
  1993.                     OUT_DEFAULT_PRECIS,;                // Output precision
  1994.                     CLIP_DEFAULT_PRECIS,;            // Clipping precision
  1995.                     DEFAULT_QUALITY,;                    // Output quality
  1996.                     DEFAULT_PITCH,;                    // Pitch and Family
  1997.                     this.FontName + Chr(0))            // Font name
  1998.         hOrgFont = BL_SelectObject(this.hDC, hFont)
  1999.         BL_GetTextExtentPoint32(this.hDC, cText, Len(cText), this.xSIZE)
  2000.         this.ItemWidth = GETU32(this.xSIZE, 0)
  2001.         this.ItemHeight = GETU32(this.xSIZE, 4)
  2002.         BL_DeleteObject(BL_SelectObject(this.hDC, hOrgFont))
  2003.         RETURN this.ItemHeight
  2004.  
  2005.     PROCEDURE UpdateProgress(nProgress)
  2006.         // Update the progress indicator on the Wizard form
  2007.  
  2008.         If this.ShowProgress
  2009.             this.ProgressObject.Value = nProgress
  2010.             BL_UpdateWindow(this.ProgressObject.hWND)
  2011.         EndIf
  2012.  
  2013.     FUNCTION StreamReport
  2014.         // Main .REP streaming function. Calls other Stream... functions.
  2015.         LOCAL nIndex, oTemp
  2016.  
  2017.         If this.CriticalError  // If critical error on last BuildReport run.
  2018.             RETURN False
  2019.         EndIf
  2020.         this.StreamCount = 0
  2021.         this.UpdateProgress((++this.StreamCount / this.ObjectCount) * 100)
  2022.         If Type("this.oReport") # "O"
  2023.             RETURN False
  2024.         EndIf
  2025.         Try
  2026.             this.hOutFile = fCreate((this.OutFilename), "W")
  2027.         Catch(Exception x)
  2028.             this.oError.OnError(x)
  2029.             this.CriticalError = True
  2030.             RETURN False
  2031.         EndTry
  2032.         If this.hOutFile < 0
  2033.             MsgBox(this.oForm.oLang.iText("NoFileCreate") + CR + CR +;
  2034.                         this.OutFilename, this.oForm.oLang.iText("WIZARDNAME"), 48)
  2035.             this.CriticalError = True
  2036.             RETURN False
  2037.         EndIf
  2038.         Try
  2039.             If Not this.StreamHeader()
  2040.                 RETURN False
  2041.             EndIf
  2042.             this.UpdateProgress((++this.StreamCount / this.ObjectCount) * 100)
  2043.             // oTemp is a temporary object used to support drill-down streaming
  2044.             // from the report class level.
  2045.             oTemp = New AssocArray()
  2046.             oTemp.xName = ""
  2047.             oTemp.Objects = New Array()
  2048.             oTemp.Objects.Add(this.oReport)
  2049.             // Now stream the entire .REP array cluster
  2050.             If Not this.StreamObject(oTemp, "")
  2051.                 RETURN False
  2052.             EndIf
  2053.             // Stream trailing object references to end of .REP file
  2054.             fWrite(this.hOutFile, Space(3) +;
  2055.                                             "this.FirstPageTemplate = this.form." +;
  2056.                                             this.oPageTemplate.xName + NEWLINE)
  2057.             fWrite(this.hOutFile, Space(3) +;
  2058.                                             "this.form." +;
  2059.                                             this.oPageTemplate.xName +;
  2060.                                             ".NextPageTemplate = this.form." +;
  2061.                                             this.oPageTemplate.xName + NEWLINE)
  2062.             For nTemp = 1 To this.oReport.aStreamFrames.Size
  2063.                 fWrite(this.hOutFile, Space(3) + "this.form." +;
  2064.                                             this.oPageTemplate.xName +;
  2065.                                             "." + this.oReport.aStreamFrames[nTemp].xName +;
  2066.                                             ".StreamSource = this.form." +;
  2067.                                             this.oStreamSource.xName + NEWLINE)
  2068.             EndFor
  2069.             fWrite(this.hOutFile, Space(3) + "this.form." +;
  2070.                                             this.oStreamSource.xName +;
  2071.                                             ".RowSet = this.form." +;
  2072.                                             this.cStreamQuery + ".RowSet" + NEWLINE)
  2073.           fWrite(this.hOutFile, "ENDCLASS" + NEWLINE + NEWLINE)
  2074.             this.UpdateProgress((++this.StreamCount / this.ObjectCount) * 100)
  2075.         Catch(RBException x)  // Program-detected errors caught here
  2076.             this.oError.OnError(x)
  2077.             this.CriticalError = True
  2078.         Catch(Exception x)    // VdB-detected errors caught here
  2079.             this.oError.OnError(x)
  2080.             this.CriticalError = True
  2081.         Finally
  2082.             fClose(this.hOutFile) // Close output file handle
  2083.             this.oForm = Null
  2084.             this.aQBEFiles = Null
  2085.             this.ProgressObject = Null
  2086.         EndTry
  2087.         RETURN Not this.CriticalError
  2088.  
  2089.     FUNCTION StreamHeader
  2090.         // Streams header comment blocks, report rendering bootstrap, and
  2091.         // class declaration statement to output file.
  2092.         LOCAL cTemp, nLen
  2093.  
  2094.         nTemp = Len(this.oForm.oLang.iText("Filename"))
  2095.       nLen = Len(this.oForm.oLang.iText("CreatedBy"))
  2096.         nTemp = IIf(nLen > nTemp, nLen, nTemp)
  2097.         nLen = Len(this.oForm.oLang.iText("CreatedFrom"))
  2098.         nTemp = IIf(nLen > nTemp, nLen, nTemp)
  2099.         nLen = Len(this.oForm.oLang.iText("CreatedOn"))
  2100.         nTemp = IIf(nLen > nTemp, nLen, nTemp)
  2101.         nLen = Len(this.oForm.oLang.iText("DataFile"))
  2102.         nTemp ++ = IIf(nLen > nTemp, nLen, nTemp)
  2103.         cTemp = this.OutFilename
  2104.         If RAt("\", cTemp) > 0
  2105.             cTemp = Right(cTemp, Len(cTemp) - RAt("\", cTemp))
  2106.         EndIf
  2107.         this.StreamComments(this.oForm.oLang.iText("Filename") + ":" +;
  2108.                         Space(nTemp - Len(this.oForm.oLang.iText("Filename"))) +;
  2109.                         cTemp + NEWLINE +;
  2110.                         this.oForm.oLang.iText("CreatedBy") + ":" +;
  2111.                         Space(nTemp - Len(this.oForm.oLang.iText("CreatedBy"))) +;
  2112.                         this.oForm.oLang.iText("WIZARDNAME") + NEWLINE +;
  2113.                         this.oForm.oLang.iText("CreatedFrom") + ":" +;
  2114.                         Space(nTemp - Len(this.oForm.oLang.iText("CreatedFrom"))) +;
  2115.                         ALLTRIM(this.inFilename) + NEWLINE +;
  2116.                         this.oForm.oLang.iText("DataFile") + ":" +;
  2117.                         Space(nTemp - Len(this.oForm.oLang.iText("DataFile"))) +;
  2118.                         ALLTRIM(this.oReport.DataFile) + NEWLINE +;
  2119.                         this.oForm.oLang.iText("CreatedOn") + ":" +;
  2120.                         Space(nTemp - Len(this.oForm.oLang.iText("CreatedOn"))) +;
  2121.                         DToC(Date()) + " " +;
  2122.                         this.oForm.oLang.iText("CreatedAt") + " " + Time(),;
  2123.                         True, True)
  2124.         fWrite(this.hOutFile, "//" + NEWLINE)
  2125.  
  2126.         If Not IsBlank(this.oReport.LabelType) Or;
  2127.                                                         Not IsBlank(this.oReport.LabelStyle)
  2128.             this.StreamComments(this.oForm.oLang.iText("LabelType") + ":  " +;
  2129.                                                             this.oReport.LabelType + NEWLINE +;
  2130.                                         this.oForm.oLang.iText("LabelStyle") + ": " +;
  2131.                                                             this.oReport.LabelStyle + NEWLINE,;
  2132.                                                                                         True, True)
  2133.             fWrite(this.hOutFile, "//" + NEWLINE)
  2134.         EndIf
  2135.  
  2136.         If Not IsBlank(this.oReport.Comments)
  2137.             this.StreamComments(this.oForm.oLang.iText("CommentsFrom") + ": " +;
  2138.                                                             this.InFilename + NEWLINE +;
  2139.                                                             this.oReport.Comments, True, True)
  2140.             fWrite(this.hOutFile, "//" + NEWLINE)
  2141.         EndIf
  2142.  
  2143.         If this.aErrors.Size > 0
  2144.                 this.StreamComments(this.oForm.oLang.iText("ExceptionLog") + ":" +;
  2145.                                                             NEWLINE, True, False)
  2146.          For nTemp = 1 To this.aErrors.Size
  2147.                 this.StreamComments(this.aErrors[nTemp], False,;
  2148.                                                                     nTemp = this.aErrors.Size)
  2149.             EndFor
  2150.             fWrite(this.hOutFile, "//" + NEWLINE)
  2151.         EndIf
  2152.  
  2153.         fWrite(this.hOutFile,;
  2154.                     "** END HEADER -- " + this.oForm.oLang.iText("NoRemoveLine") +;
  2155.                             NEWLINE +;
  2156.                     "//" + NEWLINE +;
  2157.                     "// " + this.oForm.oLang.iText("ConvertedOn") + " " +;
  2158.                             DToC(Date()) + NEWLINE +;
  2159.                     "//" + NEWLINE)
  2160.  
  2161.         fWrite(this.hOutFile,;
  2162.                     "LOCAL r" + NEWLINE +;
  2163.                     "r = new " + this.oReport.xClassName + "()" + NEWLINE +;
  2164.                     "r.render()" + NEWLINE +;
  2165.                     "CLASS " + this.oReport.xClassName + " OF REPORT" + NEWLINE)
  2166.         fWrite(this.hOutFile, NEWLINE)
  2167.         RETURN True
  2168.  
  2169.    FUNCTION StreamComments(cComm, lCommentStart, lCommentEnd)
  2170.         // Streams comment lines and
  2171.         // optionally (lCommentStart) an asterisk line before the comment block, and
  2172.         // optionally (lCommentEnd) an asterisk line after the comment block.
  2173.         // Comment line length is limited to MAXLINELEN in RptToRepConv.H
  2174.       LOCAL nLineEnd, cLine, cComments
  2175.  
  2176.         If lCommentStart
  2177.             this.StreamBannerLine()
  2178.         EndIf
  2179.         cComments = cComm
  2180.         Do While Not IsBlank(cComments)
  2181.             nLineEnd = At(LF, cComments)
  2182.             If nLineEnd > 0
  2183.                 cLine = Left(cComments, nLineEnd)
  2184.             Else
  2185.                 cLine = Left(cComments, MAXLINELEN)
  2186.             EndIf
  2187.             Do While (RAt(" ", cLine) > MAXLINELEN - 5)
  2188.                 cLine = Left(cLine, RAt(" ", cLine, 2) - 1)
  2189.             EndDo
  2190.             If (Len(cLine) > MAXLINELEN - 5) And (RAt(" ", cLine) > 0)
  2191.                 cLine = Left(cLine, RAt(" ", cLine) - 1)
  2192.             Else
  2193.                 cLine = Left(cLine, MAXLINELEN - 5)
  2194.             EndIf
  2195.             cComments = LTrim(Right(cComments, Len(cComments) - Len(cLine)))
  2196.             Do While RAt(LF, cLine) > 0
  2197.                 cLine = Left(cLine, RAt(CR, cLine) - 1)
  2198.             EndDo
  2199.             fWrite(this.hOutFile,;
  2200.                             "// " + cLine +;
  2201.                             Space((MAXLINELEN - 5) - Len(cLine)) + "//" + NEWLINE)
  2202.         EndDo
  2203.         If lCommentEnd
  2204.             this.StreamBannerLine()
  2205.         EndIf
  2206.         RETURN .T.
  2207.  
  2208.     FUNCTION StreamBannerLine
  2209.  
  2210.         RETURN fWrite(this.hOutFile, Replicate("/", MAXLINELEN) + NEWLINE)
  2211.  
  2212.     FUNCTION StreamObject(oRef, cRefChain)
  2213.         // Streams all objects in .REP array cluster.
  2214.         // Uses recursive calls to itself to support drill-down
  2215.         // streaming of contained objects and maintain the object
  2216.         // reference chain text.
  2217.         LOCAL cProperty, nIndex, nTemp, lAnyStream, lPropertyStreamed
  2218.  
  2219.         For nIndex = 1 To oRef.Objects.Size
  2220.             If Not oRef.Objects[nIndex].xClassName $ "UNKNOWN|BLANK"
  2221.                 lAnyStream = False
  2222.                 lPropertyStreamed = False
  2223.                 If oRef.Objects[nIndex].Define
  2224.                     lAnyStream = True
  2225.                     fWrite(this.hOutFile, Space(3) +;
  2226.                                         cRefChain + "." + oRef.Objects[nIndex].xName +;
  2227.                                         " = new " + oRef.Objects[nIndex].xClassName +;
  2228.                                         "(")
  2229.                     If Not oRef.Objects[nIndex].AddParentRef
  2230.                         fWrite(this.hOutFile, cRefChain)
  2231.                     EndIf
  2232.                     fWrite(this.hOutFile, ")" + NEWLINE)
  2233.                 EndIf
  2234.                 If oRef.Objects[nIndex].AddParentRef
  2235.                     lAnyStream = True
  2236.                     fWrite(this.hOutFile, Space(3) +;
  2237.                                         cRefChain + "." + oRef.Objects[nIndex].xName +;
  2238.                                         ".Parent = " + cRefChain + NEWLINE)
  2239.                 EndIf
  2240.  
  2241.                 If oRef.Objects[nIndex].Count() # 0
  2242.                     lAnyStream = True
  2243.                     lPropertyStreamed = True
  2244.                     fWrite(this.hOutFile, Space(3) +;
  2245.                                         "With (" +;
  2246.                                         IIf(Not IsBlank(cRefChain), cRefChain + ".", "") +;
  2247.                                         oRef.Objects[nIndex].xName + ")" + NEWLINE)
  2248.                     cProperty = oRef.Objects[nIndex].FirstKey
  2249.                     Do While Not Empty(cProperty)
  2250.                         fWrite(this.hOutFile,;
  2251.                                         Space(6) + cProperty + " = " +;
  2252.                                         Transform(oRef.Objects[nIndex][cProperty], "@T"))
  2253.                         cProperty = oRef.Objects[nIndex].NextKey(cProperty)
  2254.                         fWrite(this.hOutFile, NEWLINE)
  2255.                     EndDo
  2256.                     // This is a workaround to prevent streaming the
  2257.                     // Query.Active property before streaming the other
  2258.                     // Query properties which VdB can't handle.
  2259.                     // Also, see the xQuery class where the Active
  2260.                     // property is commented out.
  2261.                     If oRef.Objects[nIndex].xClassName == "QUERY" And;
  2262.                                                                                 lPropertyStreamed
  2263.                         fWrite(this.hOutFile, Space(6) + "Active = true" + NEWLINE)
  2264.                     EndIf
  2265.                     fWrite(this.hOutFile, Space(3) +;
  2266.                                                                 "EndWith" + NEWLINE)
  2267.                 EndIf
  2268.                 If lAnyStream
  2269.                     fWrite(this.hOutFile, NEWLINE)
  2270.                 EndIf
  2271.  
  2272.                 this.UpdateProgress((++this.StreamCount / this.ObjectCount) * 100)
  2273.                 If oRef.Objects[nIndex].Objects.Size > 0
  2274.                     oRef.Objects[nIndex].Objects =;
  2275.                                         this.ArrangeZOrder(oRef.Objects[nIndex].Objects)
  2276.                     If Not IsBlank(cRefChain)
  2277.                         cRefChain += "."
  2278.                     EndIf
  2279.                     cRefChain += oRef.Objects[nIndex].xName
  2280.                     this.StreamObject(oRef.ObJects[nIndex], cRefChain)
  2281.                     cRefChain = Left(cRefChain, RAt(".", cRefChain) - 1)
  2282.                 EndIf
  2283.             ElseIf (this.Debug Or this.StreamAll) And;
  2284.                                         (Not oRef.Objects[nIndex].xClassName == "BLANK")
  2285.                 For nTemp = 1 To oRef.Objects[nIndex].aComments.Size
  2286.                     fWrite(this.hOutFile, "// " +;
  2287.                                                     oRef.Objects[nIndex].aComments[nTemp] +;
  2288.                                                     NEWLINE)
  2289.                 EndFor
  2290.                 fWrite(this.hOutFile, NEWLINE)
  2291.             EndIf
  2292.         EndFor
  2293.         RETURN True
  2294.  
  2295.     FUNCTION ArrangeZOrder(aRef)
  2296.         LOCAL nInd, aTarget
  2297.  
  2298.         aTarget = New Array()
  2299.         For nInd = 1 To aRef.Size
  2300.             If aRef[nInd].xClassName $ "SHAPE|IMAGE"
  2301.                 aTarget.Add(aRef[nInd])
  2302.             EndIf
  2303.         EndFor
  2304.         For nInd = 1 To aRef.Size
  2305.             If Not aRef[nInd].xClassName $ "SHAPE|IMAGE"
  2306.                 aTarget.Add(aRef[nInd])
  2307.             EndIf
  2308.         EndFor
  2309.         RETURN aTarget
  2310.  
  2311. ENDCLASS  // ReportConverter
  2312.  
  2313.  
  2314. CLASS RBException(oParent) Of Exception
  2315. // One instance of this class handles all errors during report
  2316. // conversion and streaming.
  2317.  
  2318.     this.Filename =            Program()
  2319.     this.TitleText =            oParent.oLang.iText("WIZARDNAME")
  2320.  
  2321.     this.aMessage = New Array(0)
  2322.     this.aMessage.Add(oParent.oLang.iText("InvalidInput"))            // 10001
  2323.     this.aMessage.Add(oParent.oLang.iText("UnsupportedVersion"))    // 10002
  2324.     this.aMessage.Add(oParent.oLang.iText("OrDamagedFile"))             // 10003
  2325.     this.aMessage.Add(oParent.oLang.iText("BadRecordLength"))        // 10004
  2326.     this.aMessage.Add(oParent.oLang.iText("GenIOError"))                  // 10005
  2327.     this.aMessage.Add(oParent.oLang.iText("NoPrintDC"))                // 10006
  2328.     this.aMessage.Add(oParent.oLang.iText("NoPrintMapMode"))            // 10007
  2329.     this.aMessage.Add(oParent.oLang.iText("NoFontGDI"))                // 10008
  2330.     this.aMessage.Add(oParent.oLang.iText("NoFontDataGDI"))          // 10009
  2331.     this.aMessage.Add(oParent.oLang.iText("FieldCtMismatch"))        // 10010
  2332.     this.aMessage.Add(oParent.oLang.iText("FormulaCtMismatch"))        // 10011
  2333.     this.aMessage.Add(oParent.oLang.iText("TextCtMismatch"))            // 10012
  2334.     this.aMessage.Add(oParent.oLang.iText("NoQueryFile"))                // 10013
  2335.     this.aMessage.Add(oParent.oLang.iText("HasOLEItem"))                // 10014
  2336.  
  2337.     PROCEDURE ClearError
  2338.         this.Code =                0
  2339.         this.Message =            ""
  2340.         this.Filename =        ""
  2341.         this.LineNo =            0
  2342.         this.Filename =        Program()
  2343.  
  2344.     PROCEDURE OnError(oX)
  2345.         If oX.Code > 10000
  2346.             oX.Message = oX.aMessage[oX.Code - 10000]
  2347.         EndIf
  2348.         this.Code = oX.Code
  2349.         this.Message = oX.Message
  2350.         this.LineNo = oX.LineNo
  2351.         this.Filename = oX.Filename
  2352.         MsgBox(oX.Message + Chr(13) +;
  2353.                     "Code: " + CHARNUM(oX.Code) + ": " + Chr(13) +;
  2354.                     "In file: " + oX.Filename + Chr(13) +;
  2355.                     "Line: " + CHARNUM(oX.LineNo),;
  2356.                     this.TitleText, 48)
  2357.  
  2358. ENDCLASS  // RBException Of Exception
  2359.  
  2360.  
  2361. CLASS RepObjBase Of AssocArray
  2362. // Base class used by all templates streamed to .REP file
  2363.  
  2364.     this.VdBReportObject =    True
  2365.     this.RptFooterObject =    False
  2366.     this.Define =                True
  2367.     this.AddParentRef =        False
  2368.     this.Objects =                New Array()
  2369.     this.aaObjNums =            New AssocArray()
  2370.  
  2371.     FUNCTION NextName(cName)
  2372.         LOCAL cTemp
  2373.  
  2374.         cTemp = cName
  2375.         Do While At(" ", cTemp) > 0
  2376.             cTemp = Stuff(cTemp, At(" ", cTemp), 1, "_")
  2377.         EndDo
  2378.         If Not this.aaObjNums.IsKey(cTemp)
  2379.             this.aaObjNums[cTemp] = 1
  2380.         EndIf
  2381.         RETURN cTemp + CHARNUM(this.aaObjNums[cTemp]++)
  2382.  
  2383.     PROCEDURE SetFont(oRef)
  2384.  
  2385.         If Upper(oRef.FontName) # Upper(HTML_DEFFACE)
  2386.             this["FontName"] =        '"' + oRef.FontName + '"'
  2387.         EndIf
  2388.         If oRef.FontSize # HTML_DEFFNSZ
  2389.             this["FontSize"] =        oRef.FontSize
  2390.         EndIf
  2391.         If oRef.FontBold # HTML_DEFBOLD
  2392.             this["FontBold"] =        oRef.FontBold > 401
  2393.         EndIf
  2394.         If oRef.FontItalic # HTML_DEFITAL
  2395.             this["FontItalic"] =        oRef.FontItalic
  2396.         EndIf
  2397.         If oRef.FontUnderline # HTML_DEFUNLN
  2398.             this["FontUnderline"] =    oRef.FontUnderline
  2399.         EndIf
  2400.         If oRef.FontStrikeout # HTML_DEFSTRK
  2401.             this["FontStrikeout"] =    oRef.FontStrikeout
  2402.         EndIf
  2403.         this["Height"] =                oRef.GetItemSize("H")
  2404.         If this.IsKey("BorderStyle") And this["BorderStyle"] == "6"
  2405.             this["Height"] += 90
  2406.         EndIf
  2407.  
  2408. ENDCLASS  // RepObjBase Of AssocArray
  2409.  
  2410.  
  2411. CLASS xReport(cName) Of RepObjBase
  2412. // Main report class template
  2413.  
  2414.     this.xClassName =            cName + "REPORT"
  2415.     this.xName =                "this"
  2416.     this.Define =                False
  2417.  
  2418.     this.Title =                ""
  2419.     this.Comments =            ""
  2420.  
  2421.     this.DLLFile =                ""
  2422.     this.DataPath =            ""
  2423.     this.DataFile =            ""
  2424.     this.aTables =                New Array()
  2425.     this.aaFormulas =            New AssocArray()    // FormulaName/Formula
  2426.     this.FormulaCount =        0
  2427.     this.aCRWBands =            New Array()            // Container for CRWBand objects
  2428.     this.aStreamFrames =        New Array()            // Container for StreamFrames
  2429.  
  2430.     this.LabelType =            ""
  2431.     this.LabelStyle =            ""
  2432.  
  2433. ENDCLASS  // xReport Of RepObjBase
  2434.  
  2435.  
  2436. CLASS xQuery(cName) Of RepObjBase
  2437. // Table query object template
  2438.  
  2439.     this.xClassName =            "QUERY"
  2440.     this.xName =                cName
  2441.  
  2442.     this.AddParentRef =        True
  2443.  
  2444.     this.Indexed =                False
  2445.  
  2446.     this["SQL"] =                ""
  2447.     this["RequestLive"] =    False
  2448. // See workaround comments in StreamObject method.
  2449. // this["Active"] =            True
  2450.  
  2451. ENDCLASS  // xQuery Of RepObjBase
  2452.  
  2453.  
  2454. CLASS xRowSet Of RepObjBase
  2455. // Query.Rowset object template
  2456.  
  2457.     this.xClassName =            "ROWSET"
  2458.     this.xName =                this.xClassName
  2459.     this.Define =                False
  2460.  
  2461. ENDCLASS // xRowSet Of RepObjBase
  2462.  
  2463.  
  2464. CLASS xPrinter Of RepObjBase
  2465. // Report Printer object template
  2466.  
  2467.     this.xClassName =            "PRINTER"
  2468.     this.xName =                this.xClassName
  2469.     this.Define =                False
  2470.  
  2471.     // Set printer defaults.
  2472.     // .RPT does not specify printer settings unless
  2473.     // File|Printer Setup is used while in design mode.
  2474.     this["Color"] =            _app.Printer.Color
  2475.     this["Duplex"] =            _app.Printer.Duplex
  2476.     this["Orientation"] =    _app.Printer.Orientation
  2477.     this["PaperSize"] =        _app.Printer.PaperSize
  2478.     this["PaperSource"] =    _app.Printer.PaperSource
  2479.     this["Resolution"] =        _app.Printer.Resolution
  2480.     this["TrueTypeFonts"] =    _app.Printer.TrueTypeFonts
  2481.  
  2482. ENDCLASS  // xPrinter Of RepObjBase
  2483.  
  2484.  
  2485. CLASS xPageTemplate(cName) Of RepObjBase
  2486. // Report PageTemplate object template
  2487.  
  2488.     this.xClassName =            "PAGETEMPLATE"
  2489.     this.xName =                cName
  2490.                            
  2491.     this["Width"] =            Int(8.5 * 1440)
  2492.     this["Height"] =            Int(11 * 1440)
  2493.     // CRW defaults to .25" margins and does not stream to .RPT unless changed
  2494.     this["MarginTop"] =        Int(.25 * 1440)
  2495.     this["MarginLeft"] =        Int(.25 * 1440)
  2496.     this["MarginRight"] =    Int(.25 * 1440)
  2497.     this["MarginBottom"] =    Int(.25 * 1440)
  2498.     this["GridLineWidth"] =    0
  2499.  
  2500. ENDCLASS  // xPageTemplate() Of RepObjBase
  2501.  
  2502.  
  2503. CLASS xStreamFrame(cName) Of RepObjBase
  2504. // Report StreamFrame object template
  2505.  
  2506.     this.xClassName =            "STREAMFRAME"
  2507.     this.xName =                cName
  2508.  
  2509.     this["Metric"] =            1
  2510.     this["Width"] =            0
  2511.     this["Height"] =            0
  2512.  
  2513. ENDCLASS  // xStreamFrame Of RepObjBase
  2514.  
  2515.  
  2516. CLASS xStreamSource(cName) Of RepObjBase
  2517. // Report StreamSource object template
  2518.  
  2519.     this.xClassName =            "STREAMSOURCE"
  2520.     this.xName =                cName
  2521.  
  2522. ENDCLASS  // xStreamSource Of RepObjBase
  2523.  
  2524.  
  2525. CLASS xGroup(cName) Of RepObjBase
  2526. // Group object template
  2527.  
  2528.     this.xClassName =        "GROUP"
  2529.     this.xName =            cName
  2530.  
  2531.     this.HeaderBand =        New xBand("HEADER")
  2532.     this.Objects.Add(this.HeaderBand)
  2533.     this.FooterBand =        New xBand("FOOTER")
  2534.     this.Objects.Add(this.FooterBand)
  2535.  
  2536. ENDCLASS  // xGroup Of RepObjBase
  2537.  
  2538. CLASS xReportGroup Of RepObjBase
  2539. // ReportGroup object template
  2540.  
  2541.     this.xClassName =        "REPORTGROUP"
  2542.     this.xName =            this.xClassName
  2543.  
  2544.     this.Define =            False
  2545.  
  2546.     this.HeaderBand =                New xBand("HEADER")
  2547.     this.Objects.Add(this.HeaderBand)
  2548.     this.FooterBand =                New xBand("FOOTER")
  2549.     this.Objects.Add(this.FooterBand)
  2550.  
  2551. ENDCLASS  // xReportGroup Of xGroup
  2552.  
  2553.  
  2554. CLASS xBand(cName) Of RepObjBase
  2555. // Band object template
  2556. // Used for all bands in .REP file
  2557.  
  2558.     this.xClassName =        "BAND"
  2559.     this.xName =            cName + this.xClassName
  2560.  
  2561.     this.Define =            False
  2562.  
  2563. ENDCLASS  // xBand Of RepObjBase
  2564.  
  2565.  
  2566. CLASS xText Of RepObjBase
  2567. // Text object template
  2568.  
  2569.     this.xClassName =        "TEXT"
  2570.     this.xName =            ""
  2571.     this.AgType =            ""
  2572.     this.AgError =            ""
  2573.  
  2574.     this["ColorNormal"] = '"BtnText"'
  2575.     this["Metric"] =        1
  2576.     this["Text"] =            ""
  2577.  
  2578. ENDCLASS  // xText Of RepObjBase
  2579.  
  2580.  
  2581. CLASS xLine(cName) Of RepObjBase
  2582. // Line object template
  2583.  
  2584.     this.xClassName =        "LINE"
  2585.     this.xName =            cName
  2586.  
  2587.     this["Metric"] =        1
  2588.  
  2589. ENDCLASS  // xLine Of RepObjBase
  2590.  
  2591.  
  2592. CLASS xShape(cName) Of RepObjBase
  2593. // Shape object template
  2594.  
  2595.     this.xClassName =        "SHAPE"
  2596.     this.xName =            cName
  2597.  
  2598.     this["ShapeStyle"] =    1
  2599.  
  2600. ENDCLASS  // xShape Of RepObjBase
  2601.  
  2602.  
  2603. CLASS xImage(cName) Of RepObjBase
  2604. // Image object template
  2605.  
  2606.     this.xClassName =        "IMAGE"
  2607.     this.xName =            cName
  2608.  
  2609.     this["Metric"] =        1
  2610.  
  2611. ENDCLASS  // xImage Of RepObjBase
  2612.  
  2613.  
  2614. CLASS xBlank(cName) Of RepObjBase
  2615. // Special template used to occupy blank vertical
  2616. // space which is used when vertically justifying
  2617. // the report objects (Top/Height properties) after
  2618. // the full .RPT file has been read.
  2619. // This template is not streamed to the .REP file.
  2620.  
  2621.     this.xClassName =        "BLANK"
  2622.     this.xName =            cName
  2623.     this.AgType =            ""
  2624.  
  2625. ENDCLASS  // xBlank Of RepObjBase
  2626.  
  2627.  
  2628. CLASS RecordStream(nWhere, nID, cDesc, xHEX) Of RepObjBase
  2629. // Special template used to stream .RPT file information to
  2630. // the .REP file in the form of comments when in Debug or
  2631. // StreamAll mode.
  2632.     LOCAL xTemp, cChars, cHex, x, cSpace, x
  2633.  
  2634.     this.xClassName =        "UNKNOWN"
  2635.     this.xName =            this.xClassName
  2636.  
  2637.  
  2638.     this.aComments = New Array()
  2639.     this.aComments.Add(cDesc + " [x" + IToH(nID, 4) + "]" +;
  2640.                            "  At: x" + IToH((nWhere - 4) - Len(xHEX), 4) +;
  2641.                            "  Length: x" + IToH(Len(xHEX), 4))
  2642.     cChars = ""
  2643.     cHex = ""
  2644.     For x = 1 To Len(xHex)
  2645.         cChars += IIf((Asc(SubStr(xHEX, x, 1)) < 32) Or;
  2646.                                      (Asc(SubStr(xHEX, x, 1)) > 127),;
  2647.                                         ".", SubStr(xHEX, x, 1))
  2648.         cHex += IToH(Asc(SubStr(xHEX, x, 1)), 2) + " "
  2649.         If Mod(x, 16) = 0
  2650.             this.aComments.Add(cHex + " " + cChars)
  2651.             cChars = ""
  2652.             cHex = ""
  2653.         ElseIf Mod(x, 8) = 0
  2654.             cChars += " "
  2655.             cHex += " "
  2656.         EndIf
  2657.     EndFor
  2658.     x = IIf(Len(cChars) < 9, Len(cChars), Len(cChars) - 1)
  2659.     cSpace = Space((16 - x) * 3) + IIf(x < 8, "  ", " ")
  2660.     this.aComments.Add(cHex + cSpace + cChars)
  2661.  
  2662. ENDCLASS  // RecordStream Of RepObjBase
  2663.  
  2664.  
  2665. CLASS DataTable Of AssocArray()
  2666. // Special class used to hold information items
  2667. // regarding data tables used by report.
  2668. // The AssocArray elements are indexed by data
  2669. // field name, and the contents are the data
  2670. // field data type.
  2671. // Not streamed to .REP file.
  2672.  
  2673.     this.TableName =            ""
  2674.     this.Alias =                ""
  2675.     this.ParentTable =        ""
  2676.     this.ParentField =        ""
  2677.     this.Order =                ""
  2678.     this.Error =                ""
  2679.     this.Tag =                    ""
  2680.     this.aOrders =                New OrderArray()    // Storage for field sorts
  2681.     this.aGroups =                New Array()            // Storage for group fields
  2682.  
  2683. ENDCLASS  // DataTable Of AssocArray
  2684.  
  2685.  
  2686. CLASS OrderArray Of Array()
  2687. // Array class used to accumulate SET ORDER TO...
  2688. // information used to stream SQL ORDER BY...
  2689. // Not streamed to .REP file.
  2690.  
  2691.     PROCEDURE Add(cExpr, cOrder)
  2692.     LOCAL nInd
  2693.  
  2694.         For nInd = 1 To this.Size / 2
  2695.             If this[nInd, 1] == cExpr
  2696.                 RETURN
  2697.             EndIf
  2698.         EndFor
  2699.         SUPER::Add(cExpr)
  2700.         SUPER::Add(cOrder)
  2701.  
  2702. ENDCLASS  // OrderArray Of Array
  2703.  
  2704.  
  2705. CLASS CRWBase Of Array
  2706. // Base class used by following classes which
  2707. // accumulate various information elements while
  2708. // the .RPT file is being read.
  2709. // Not streamed to .REP file.
  2710.  
  2711.  
  2712.     this.VdBReportObject =     False
  2713.     this.Top =                    0
  2714.     this.Height =                0
  2715.     this.Width =                0
  2716.  
  2717. ENDCLASS  // CRWBase Of Array
  2718.  
  2719.  
  2720. CLASS CRWBand(xTEMP) Of CRWBase
  2721. // .RPT report band information.
  2722. // Not streamed to .REP file.
  2723.  
  2724.     this.ID =                            MAKEU16(xTEMP, 3)
  2725.     this.Visible =                        Not MAKEU16(xTEMP, 5) = 0
  2726.     this.NewPageBefore =             Not MAKEU16(xTEMP, 7) = 0
  2727.     this.NewPageAfter =                Not MAKEU16(xTEMP, 9) = 0
  2728.     this.KeepSectionTogether =        Not MAKEU16(xTEMP, 11) = 0
  2729.     this.SuppressBlankLines =        Not MAKEU16(xTEMP, 13) = 0
  2730.     this.ResetPageNumberAfter =    Not MAKEU16(xTEMP, 15) = 0
  2731.     this.PrintAtBottomOfPage =        Not MAKEU16(xTEMP, 17) = 0
  2732.     this.FormatWithMultColumns =    Not MAKEU16(xTEMP, 19) = 0
  2733.  
  2734. ENDCLASS // CRWBand Of CRWBase
  2735.  
  2736.  
  2737. CLASS CRWLine Of CRWBase
  2738. // .RPT band line information
  2739. // Not streamed to .REP file.
  2740.  
  2741.     this.HTMLText =            "'<pre>"
  2742.  
  2743.     PROCEDURE PositionObjectsToBaseline(nMaxWidth)
  2744.         LOCAL nIndex, nTemp
  2745.  
  2746.         For nIndex = 1 To this.Size
  2747.             nTemp = this.Top + this.Height - this[nIndex]["Height"]
  2748.             If nTemp # 0
  2749.                 this[nIndex]["Top"] = this.Top + this.Height -;
  2750.                                                             this[nIndex]["Height"]
  2751.             EndIf
  2752.             If this[nIndex].IsKey("Left") And this[nIndex].IsKey("Width")
  2753.                 If this[nIndex]["Left"] + this[nIndex]["Width"] > nMaxWidth
  2754.                     this[nIndex]["Left"] = nMaxWidth - this[nIndex]["Width"]
  2755.                 EndIf
  2756.             EndIf
  2757.         EndFor
  2758.  
  2759.     PROCEDURE SetSuppressIfBlank
  2760.         LOCAL nIndex
  2761.         For nIndex = 1 To this.Size
  2762.             this[nIndex]["SuppressIfBlank"] = True
  2763.         EndFor
  2764.  
  2765. ENDCLASS  // CRWLine Of CRWBase
  2766.  
  2767.  
  2768. CLASS RGBTripleColors Of AssocArray
  2769. // Array used to convert RGB Triple color values
  2770. // in the .RPT file to JavaScript color tags.
  2771. //
  2772. // Note: The hexadecimal values used as the array
  2773. // index are in BBGGRR order which is the order
  2774. // that they are stored in the .RPT file.
  2775. // This template is not streamed to the .REP file.
  2776. // However, the color tags retrieved from this
  2777. // class are streamed to the ColorNormal properties
  2778. // of objects if a match is found. If a match is
  2779. // not found, the hexadecimal BBGGRR value is
  2780. // streamed.
  2781. //
  2782. // For more information regarding JavaScript color
  2783. // tags and hexadecimal color values, see the VdB 7
  2784. // online help 'ColorNormal' topic.
  2785.  
  2786.     this["FFF8F0"] = "aliceblue"
  2787.     this["D7EBFA"] = "antiquewhite"
  2788.     this["FFFF00"] = "aqua"
  2789.     this["D4FF7F"] = "aquamarine"
  2790.     this["FFFFF0"] = "azure"
  2791.     this["DCF5F5"] = "beige"
  2792.     this["C4E4FF"] = "bisque"
  2793.     this["000000"] = "black"
  2794.     this["CDEBFF"] = "blanchedalmond"
  2795.     this["FF0000"] = "blue"
  2796.     this["E22B8A"] = "blueviolet"
  2797.     this["2A2AA5"] = "brown"
  2798.     this["87B8DE"] = "burlywood"
  2799.     this["A09E5F"] = "cadetblue"
  2800.     this["00FF7F"] = "chartreuse"
  2801.     this["1E69D2"] = "chocolate"
  2802.     this["507FFF"] = "coral"
  2803.     this["ED9564"] = "cornflowerblue"
  2804.     this["DCF8FF"] = "cornsilk"
  2805.     this["3C14DC"] = "crimson"
  2806.     this["FFFF00"] = "cyan"
  2807.     this["8B0000"] = "darkblue"
  2808.     this["8B8B00"] = "darkcyan"
  2809.     this["0B86B8"] = "darkgoldenrod"
  2810.     this["A9A9A9"] = "darkgray"
  2811.     this["006400"] = "darkgreen"
  2812.     this["6BB7BD"] = "darkkhaki"
  2813.     this["8B008B"] = "darkmagenta"
  2814.     this["2F6B55"] = "darkolivegreen"
  2815.     this["008CFF"] = "darkorange"
  2816.     this["CC3299"] = "darkorchid"
  2817.     this["00008B"] = "darkred"
  2818.     this["7A96E9"] = "darksalmon"
  2819.     this["8FBC8F"] = "darkseagreen"
  2820.     this["8B3D48"] = "darkslateblue"
  2821.     this["4F4F2F"] = "darkslategray"
  2822.     this["D1CE00"] = "darkturquoise"
  2823.     this["D30094"] = "darkviolet"
  2824.     this["9314FF"] = "deeppink"
  2825.     this["FFBF00"] = "deepskyblue"
  2826.     this["696969"] = "dimgray"
  2827.     this["FF901E"] = "dodgerblue"
  2828.     this["2222B2"] = "firebrick"
  2829.     this["F0FAFF"] = "floralwhite"
  2830.     this["228B22"] = "forestgreen"
  2831.     this["FF00FF"] = "fuchsia"
  2832.     this["DCDCDC"] = "gainsboro"
  2833.     this["FFF8F8"] = "ghostwhite"
  2834.     this["00D7FF"] = "gold"
  2835.     this["20A5DA"] = "goldenrod"
  2836.     this["808080"] = "gray"
  2837.     this["008000"] = "green"
  2838.     this["2FFFAD"] = "greenyellow"
  2839.     this["F0FFF0"] = "honeydew"
  2840.     this["B469FF"] = "hotpink"
  2841.     this["5C5CCD"] = "indianred"
  2842.     this["82004B"] = "indigo"
  2843.     this["F0FFFF"] = "ivory"
  2844.     this["8CE6F0"] = "khaki"
  2845.     this["FAE6E6"] = "lavender"
  2846.     this["F5F0FF"] = "lavenderblush"
  2847.     this["00FC7C"] = "lawngreen"
  2848.     this["CDFAFF"] = "lemonchiffon"
  2849.     this["E6D8AD"] = "lightblue"
  2850.     this["8080F0"] = "lightcoral"
  2851.     this["FFFFE0"] = "lightcyan"
  2852.     this["D2FAFA"] = "lightgoldenrodyellow"
  2853.     this["90EE90"] = "lightgreen"
  2854.     this["D3D3D3"] = "lightgrey"
  2855.     this["C1B6FF"] = "lightpink"
  2856.     this["7AA0FF"] = "lightsalmon"
  2857.     this["AAB220"] = "lightseagreen"
  2858.     this["FACE87"] = "lightskyblue"
  2859.     this["998877"] = "lightslategray"
  2860.     this["DEC4B0"] = "lightsteelblue"
  2861.     this["E0FFFF"] = "lightyellow"
  2862.     this["00FF00"] = "lime"
  2863.     this["32CD32"] = "limegreen"
  2864.     this["E6F0FA"] = "linen"
  2865.     this["FF00FF"] = "magenta"
  2866.     this["000080"] = "maroon"
  2867.     this["AACD66"] = "mediumaquamarine"
  2868.     this["CD0000"] = "mediumblue"
  2869.     this["D355BA"] = "mediumorchid"
  2870.     this["DB7093"] = "mediumpurple"
  2871.     this["71B33C"] = "mediumseagreen"
  2872.     this["EE687B"] = "mediumslateblue"
  2873.     this["9AFA00"] = "mediumspringgreen"
  2874.     this["CCD148"] = "mediumturquoise"
  2875.     this["8515C7"] = "mediumvioletred"
  2876.     this["701919"] = "midnightblue"
  2877.     this["FAFFF5"] = "mintcream"
  2878.     this["E1E4FF"] = "mistyrose"
  2879.     this["B5E4FF"] = "moccasin"
  2880.     this["ADDEFF"] = "navajowhite"
  2881.     this["800000"] = "navy"
  2882.     this["E6F5FD"] = "oldlace"
  2883.     this["008080"] = "olive"
  2884.     this["238E6B"] = "olivedrab"
  2885.     this["00A5FF"] = "orange"
  2886.     this["0045FF"] = "orangered"
  2887.     this["D670DA"] = "orchid"
  2888.     this["AAE8EE"] = "palegoldenrod"
  2889.     this["98FB98"] = "palegreen"
  2890.     this["EEEEAF"] = "paleturquoise"
  2891.     this["9370DB"] = "palevioletred"
  2892.     this["D5EFFF"] = "papayawhip"
  2893.     this["B9DAFF"] = "peachpuff"
  2894.     this["3F85CD"] = "peru"
  2895.     this["CBC0FF"] = "pink"
  2896.     this["DDA0DD"] = "plum"
  2897.     this["E6E0B0"] = "powderblue"
  2898.     this["800080"] = "purple"
  2899.     this["0000FF"] = "red"
  2900.     this["8F8FBC"] = "rosybrown"
  2901.     this["E16941"] = "royalblue"
  2902.     this["13458B"] = "saddlebrown"
  2903.     this["7280FA"] = "salmon"
  2904.     this["60A4F4"] = "sandybrown"
  2905.     this["578B2E"] = "seagreen"
  2906.     this["EEF5FF"] = "seashell"
  2907.     this["2D52A0"] = "sienna"
  2908.     this["C0C0C0"] = "silver"
  2909.     this["EBCE87"] = "skyblue"
  2910.     this["CD5A6A"] = "slateblue"
  2911.     this["908070"] = "slategray"
  2912.     this["FAFAFF"] = "snow"
  2913.     this["7FFF00"] = "springgreen"
  2914.     this["B48246"] = "steelblue"
  2915.     this["8CB4D2"] = "tan"
  2916.     this["808000"] = "teal"
  2917.     this["D8BFD8"] = "thistle"
  2918.     this["4763FF"] = "tomato"
  2919.     this["D0E040"] = "turquoise"
  2920.     this["EE82EE"] = "violet"
  2921.     this["B3DEF5"] = "wheat"
  2922.     this["FFFFFF"] = "white"
  2923.     this["F5F5F5"] = "whitesmoke"
  2924.     this["00FFFF"] = "yellow"
  2925.     this["32CD9A"] = "yellowgreen"
  2926.  
  2927. ENDCLASS  // RGBTripleColors Of AssocArray
  2928.  
  2929. // EOF: RepBuild.CC
  2930.  
  2931.