diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 1e5e06ad9..2e7e515ba 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -41,32 +41,6 @@ type TsWorksheet = class; TsWorkbook = class; - {@@ The record TRow contains information about a spreadsheet row: - @param Row The index of the row (beginning with 0) - @param Height The height of the row (expressed in the units defined by - the workbook) - @param RowHeightType Specifies default, automatic or custom row height } - TRow = record - Row: Cardinal; - Height: Single; - RowHeightType: TsRowHeightType; - end; - - {@@ Pointer to a TRow record } - PRow = ^TRow; - - {@@ The record TCol contains information about a spreadsheet column: - @param Col The index of the column (beginning with 0) - @param Width The width of the column (expressed in the units defined in the workbook) - Only columns with non-default widths have a column record. } - TCol = record - Col: Cardinal; - Width: Single; - end; - - {@@ Pointer to a TCol record } - PCol = ^TCol; - {@@ Worksheet user interface options: @param soShowGridLines Show or hide the grid lines in the spreadsheet @param soShowHeaders Show or hide the column or row headers of the spreadsheet @@ -200,6 +174,10 @@ type function GetNumberFormatAttributes(ACell: PCell; out ADecimals: Byte; out ACurrencySymbol: String): Boolean; + function GetEffectiveCellFormatIndex(ACell: PCell): Integer; + function GetPointerToEffectiveCellFormat(ARow, ACol: Cardinal): PsCellFormat; overload; + function GetPointerToEffectiveCellFormat(ACell: PCell): PsCellFormat; overload; + function ReadUsedFormatting(ACell: PCell): TsUsedFormattingFields; function ReadBackground(ACell: PCell): TsFillPattern; function ReadBackgroundColor(ACell: PCell): TsColor; @@ -438,10 +416,12 @@ type function GetCellCountInRow(ARow: Cardinal): Cardinal; function GetCellCountInCol(ACol: Cardinal): Cardinal; function GetRow(ARow: Cardinal): PRow; + function GetRowFormatIndex(ARow: Cardinal): Integer; function GetRowHeight(ARow: Cardinal; AUnits: TsSizeUnits): Single; overload; function GetRowHeight(ARow: Cardinal): Single; overload; deprecated 'Use version with parameter AUnits.'; function GetRowHeightType(ARow: Cardinal): TsRowHeightType; function GetCol(ACol: Cardinal): PCol; + function GetColFormatIndex(ACol: Cardinal): Integer; function GetColWidth(ACol: Cardinal; AUnits: TsSizeUnits): Single; overload; function GetColWidth(ACol: Cardinal): Single; overload; deprecated 'Use version with parameter AUnits.'; procedure DeleteCol(ACol: Cardinal); @@ -457,11 +437,13 @@ type procedure WriteDefaultColWidth(AValue: Single; AUnits: TsSizeUnits); procedure WriteDefaultRowHeight(AValue: Single; AUnits: TsSizeUnits); procedure WriteRowInfo(ARow: Cardinal; AData: TRow); + procedure WriteRowFormatIndex(ARow: Cardinal; AFormatIndex: Integer); procedure WriteRowHeight(ARow: Cardinal; AHeight: Single; AUnits: TsSizeUnits; ARowHeightType: TsRowHeightType = rhtCustom); overload; procedure WriteRowHeight(ARow: Cardinal; AHeight: Single; ARowHeightType: TsRowHeightType = rhtCustom); overload; deprecated 'Use version with parameter AUnits'; procedure WriteColInfo(ACol: Cardinal; AData: TCol); + procedure WriteColFormatIndex(ACol: Cardinal; AFormatIndex: Integer); procedure WriteColWidth(ACol: Cardinal; AWidth: Single; AUnits: TsSizeUnits); overload; procedure WriteColWidth(ACol: Cardinal; AWidth: Single); overload; deprecated 'Use version with parameter AUnits'; @@ -2873,6 +2855,70 @@ begin end; end; +{@@ ---------------------------------------------------------------------------- + Returns the index of the effective cell format to be used at the specified + cell. + + "Effective" cell format means: At first, look for the cell format. + If it is default, look for the row format. If it is default, look for + the column format. (see "excelfileformat", p. 89) +-------------------------------------------------------------------------------} +function TsWorksheet.GetEffectiveCellFormatIndex(ACell: PCell): Integer; +begin + Result := 0; + if ACell <> nil then + Result := ACell^.FormatIndex; + if Result = 0 then + Result := GetRowFormatIndex(ACell^.Row); + if Result = 0 then + Result := GetColFormatIndex(ACell^.Col); +end; + +{@@ ---------------------------------------------------------------------------- + Returns a pointer to the effective cell format to be used at the cell in + ARow and ACol. + + "Effective" cell format means: At first, look for the cell format. + If it is default, look for the row format. If it is default, look for + the column format. (see "excelfileformat", p. 89) +-------------------------------------------------------------------------------} +function TsWorksheet.GetPointerToEffectiveCellFormat(ARow, ACol: Cardinal): PsCellFormat; +var + cell: PCell; + fmtIndex: Integer; +begin + cell := FindCell(ARow, ACol); + if (cell <> nil) and (cell^.FormatIndex > 0) then + fmtIndex := cell^.FormatIndex + else begin + fmtIndex := GetRowFormatIndex(ARow); + if fmtIndex = 0 then + fmtIndex := GetColFormatIndex(ACol); + end; + Result := FWorkbook.GetPointerToCellFormat(fmtIndex); +end; + +{@@ ---------------------------------------------------------------------------- + Mainly like GetPointerToEffectiveCellFormat(ARow, ACol), but avoids looking + for the cell if ACell <> nil +-------------------------------------------------------------------------------} +function TsWorksheet.GetPointerToEffectiveCellFormat(ACell: PCell): PsCellFormat; +var + fmtIndex: Integer; +begin + fmtIndex := 0; + if (ACell <> nil) then begin + if (ACell^.FormatIndex > 0) then + fmtIndex := ACell^.FormatIndex + else begin + fmtIndex := GetRowFormatIndex(ACell^.Row); + if fmtIndex = 0 then + fmtIndex := GetColFormatIndex(ACell^.Col); + end; + end; + Result := FWorkbook.GetPointerToCellFormat(fmtIndex); +end; + {@@ ---------------------------------------------------------------------------- Reads the set of used formatting fields of a cell. @@ -4545,6 +4591,7 @@ var isMixed: Boolean; rtParams: TsRichTextParams; plain: String; + fmtIndex: Integer; begin if ACell = nil then exit; @@ -4564,8 +4611,10 @@ begin WriteNumberFormat(ACell, nfText); end; - fmt := Workbook.GetCellFormat(ACell^.FormatIndex); + fmtIndex := GetEffectiveCellFormatIndex(ACell); + fmt := Workbook.GetCellFormat(fmtIndex); numFmtParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex); + ACell^.FormatIndex := fmtIndex; isPercent := Pos('%', AValue) = Length(AValue); if isPercent then Delete(AValue, Length(AValue), 1); @@ -6430,6 +6479,28 @@ begin end; end; +{@@ ---------------------------------------------------------------------------- + Returns the index to the cell format to be used for a given column. + If there is no column record then the default format (index 0) is used. + + @param ACol Index of the column considered + @return Index of the format into the workbook's FCellFormatList. This format + will be used for formatting a cell if itself does not have a + non-zero format index, and if there is no row format either. +-------------------------------------------------------------------------------} +function TsWorksheet.GetColFormatIndex(ACol: Cardinal): Integer; +var + col: PCol; +begin + Result := 0; // Default format has index 0 + if ACol <> UNASSIGNED_ROW_COL_INDEX then + begin + col := FindCol(ACol); + if col <> nil then + Result := col^.FormatIndex + end; +end; + {@@ ---------------------------------------------------------------------------- Returns the width of the given column. If there is no column record then the default column width is returned. @@ -6460,6 +6531,28 @@ begin Result := GetColWidth(ACol, suChars); end; +{@@ ---------------------------------------------------------------------------- + Returns the index to the cell format to be used for a given row. + If there is no row record then the default format (index 0) is returned. + + @param ARow Index of the row considered + @return Index of the format into the workbook's FCellFormatList. This format + will be used for formatting a cell if itself does not have a + non-zero format index. +-------------------------------------------------------------------------------} +function TsWorksheet.GetRowFormatIndex(ARow: Cardinal): Integer; +var + row: PRow; +begin + Result := 0; // Default format has index 0 + if ARow <> UNASSIGNED_ROW_COL_INDEX then + begin + row := FindRow(ARow); + if row <> nil then + Result := row^.FormatIndex + end; +end; + {@@ ---------------------------------------------------------------------------- Returns the height of the given row. If there is no row record then the default row height is returned @@ -6905,24 +6998,40 @@ end; {@@ ---------------------------------------------------------------------------- Writes a row record for the row at a given index to the spreadsheet. - Currently the row record contains only the row height (and the row index, - of course). + The row record contains info on the row height and the row format index. Creates a new row record if it does not yet exist. @param ARow Index of the row record which will be created or modified - @param AData Data to be written. Expected to be already in the units - defined for the workbook - Note that the row height value can be negative to indicate - that this is an auto-calculated value (i.e. the value can - change for example when the font size changes). + @param AData Data to be written. Row height expected to be already in the + units defined for the workbook. -------------------------------------------------------------------------------} procedure TsWorksheet.WriteRowInfo(ARow: Cardinal; AData: TRow); var - AElement: PRow; + lRow: PRow; begin - AElement := GetRow(ARow); - AElement^.Height := AData.Height; + lRow := GetRow(ARow); + lRow^.Height := AData.Height; + lRow^.RowHeightType := AData.RowHeightType; + lRow^.FormatIndex := AData.FormatIndex; +end; + +{@@ ---------------------------------------------------------------------------- + Sets the cell format index for a specific row. + Creates a new row record if it does not yet exist. + + @param ARow Index of the row to be considered + @param AFormatIndex Index into the workbook's FCellFormatList. This format + will be used if a cell has default format index (0). +-------------------------------------------------------------------------------} +procedure TsWorksheet.WriteRowFormatIndex(ARow: Cardinal; AFormatIndex:Integer); +var + lRow: PRow; +begin + if ARow = UNASSIGNED_ROW_COL_INDEX then + exit; + lRow := GetRow(ARow); + lRow^.FormatIndex := AFormatIndex; end; {@@ ---------------------------------------------------------------------------- @@ -6938,13 +7047,13 @@ end; procedure TsWorksheet.WriteRowHeight(ARow: Cardinal; AHeight: Single; AUnits: TsSizeUnits; ARowHeightType: TsRowHeightType = rhtCustom); var - AElement: PRow; + lRow: PRow; begin if ARow = UNASSIGNED_ROW_COL_INDEX then exit; - AElement := GetRow(ARow); - AElement^.Height := FWorkbook.ConvertUnits(AHeight, AUnits, FWorkbook.FUnits); - AElement^.RowHeightType := ARowHeightType; + lRow := GetRow(ARow); + lRow^.Height := FWorkbook.ConvertUnits(AHeight, AUnits, FWorkbook.FUnits); + lRow^.RowHeightType := ARowHeightType; end; {@@ ---------------------------------------------------------------------------- @@ -6961,22 +7070,42 @@ begin end; {@@ ---------------------------------------------------------------------------- - Writes a column record for the column at a given index to the spreadsheet. - Currently the column record contains only the column width (and the column - index, of course). + Writes a column record for the column at a specific index to the spreadsheet. + The column record contains info on the column width and the format index. Creates a new column record if it does not yet exist. @param ACol Index of the column record which will be created or modified - @param AData Data to be written (essentially column width). The column - width is already in the units defined for the workbook. + @param AData Data to be written. The column width must already be in + the units defined for the workbook. -------------------------------------------------------------------------------} procedure TsWorksheet.WriteColInfo(ACol: Cardinal; AData: TCol); var - AElement: PCol; + lCol: PCol; begin - AElement := GetCol(ACol); - AElement^.Width := AData.Width; + lCol := GetCol(ACol); + lCol^.Width := AData.Width; + lCol^.ColWidthType := AData.ColWidthType; + lCol^.FormatIndex := AData.FormatIndex; +end; + +{@@ ---------------------------------------------------------------------------- + Sets the cell format index for a specific column. + Creates a new column record if it does not yet exist. + + @param ACol Index of the column to be considered + @param AFormatIndex Index into the workbook's FCellFormatList. This format + will be used if a cell has default format index (0) and + if there is no specific default row format. +-------------------------------------------------------------------------------} +procedure TsWorksheet.WriteColFormatIndex(ACol: Cardinal; AFormatIndex:Integer); +var + lCol: PCol; +begin + if ACol = UNASSIGNED_ROW_COL_INDEX then + exit; + lCol := GetCol(ACol); + lCol^.FormatIndex := AFormatIndex; end; {@@ ---------------------------------------------------------------------------- @@ -6990,12 +7119,12 @@ end; procedure TsWorksheet.WriteColWidth(ACol: Cardinal; AWidth: Single; AUnits: TsSizeUnits); var - AElement: PCol; + lCol: PCol; begin if ACol = UNASSIGNED_ROW_COL_INDEX then exit; - AElement := GetCol(ACol); - AElement^.Width := FWorkbook.ConvertUnits(AWidth, AUnits, FWorkbook.FUnits); + lCol := GetCol(ACol); + lCol^.Width := FWorkbook.ConvertUnits(AWidth, AUnits, FWorkbook.FUnits); end; {@@ ---------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index f2d5d9ee9..19c9938d4 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -498,7 +498,7 @@ type TsWorksheetGrid = class(TsCustomWorksheetGrid) published // inherited from TsCustomWorksheetGrid - {@@ Automatically recalculates the worksheet if a cell value changes. } + {@@ Automatically recalculates the worksheet formulas if a cell value changes. } property AutoCalc; {@@ Automatically expand grid dimensions } property AutoExpand default [aeData, aeNavigation]; @@ -1307,8 +1307,8 @@ begin if (cell = nil) or not (cell^.ContentType in [cctUTF8String]) then // ... non-label cells exit; - fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); - +// fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(cell); if (uffWordWrap in fmt^.UsedFormattingFields) then // ... word-wrap exit; if (uffTextRotation in fmt^.UsedFormattingFields) and // ... vertical text @@ -1717,10 +1717,13 @@ begin r := ARow - FHeaderCount; c := ACol - FHeaderCount; + fmt := Worksheet.GetPointerToEffectiveCellFormat(r, c); lCell := Worksheet.FindCell(r, c); - if lCell <> nil then - begin - fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); + + //if lCell <> nil then + //begin + +// fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); // numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); // Background color @@ -1760,7 +1763,7 @@ begin end; // Font - if Worksheet.HasHyperlink(lCell) then + if (lcell <> nil) and Worksheet.HasHyperlink(lCell) then fnt := Workbook.GetHyperlinkFont else fnt := Workbook.GetDefaultFont; @@ -1771,7 +1774,7 @@ begin Canvas.Font.Height := Round(ZoomFactor * Canvas.Font.Height); // Wordwrap, text alignment and text rotation are handled by "DrawTextInCell". - end; + //end; end; if IsSelected then @@ -1997,7 +2000,8 @@ begin DrawBorderLine(ARect.Bottom-1, ARect, drawHor, bs); if ACell <> nil then begin - fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(ACell); +// fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); { if Worksheet.IsMergeBase(ACell) then begin @@ -2212,7 +2216,8 @@ begin then Continue; // Overflow possible from non-merged, non-right-aligned, horizontal label cells - fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); +// fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(cell); if (not Worksheet.IsMerged(cell)) and (cell^.ContentType = cctUTF8String) and not (uffTextRotation in fmt^.UsedFormattingFields) and @@ -2239,7 +2244,8 @@ begin then continue; // Overflow possible from non-merged, horizontal, non-left-aligned label cells - fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); +// fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(cell); if (not Worksheet.IsMerged(cell)) and (cell^.ContentType = cctUTF8String) and not (uffTextRotation in fmt^.UsedFormattingFields) and @@ -2496,15 +2502,7 @@ begin ts.Layout := tlCenter; ts.Opaque := false; Canvas.TextStyle := ts; - { - writeLn('HEADER'); - writeln(Format('1 - col=%d, row=%d, font size=%d', [acol, arow, canvas.font.size])); - } inherited DrawCellText(aCol, aRow, aRect, aState, GetCellText(ACol,ARow)); - { - writeln(GetCellText(ACol, ARow)); - writeln(Format('2 - col=%d, row=%d, font size=%d', [acol, arow, canvas.font.size])); - } exit; end; @@ -2516,7 +2514,8 @@ begin if txt = '' then exit; - fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); +// fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(lCell); wrapped := (uffWordWrap in fmt^.UsedFormattingFields) or (fmt^.TextRotation = rtStacked); RTL := IsRightToLeft; if (uffBiDi in fmt^.UsedFormattingFields) then @@ -2702,9 +2701,10 @@ begin if (Worksheet = nil) or (ACell = nil) then exit; + fmt := Worksheet.GetPointerToEffectiveCellFormat(ACell); with ACell^ do begin - fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); +// fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); if Col > 0 then SetNeighborBorder(Row, Col-1, cbEast, fmt^.BorderStyles[cbWest], cbWest in fmt^.Border); SetNeighborBorder(Row, Col+1, cbWest, fmt^.BorderStyles[cbEast], cbEast in fmt^.Border); @@ -3121,7 +3121,8 @@ begin DoPrepareCanvas(ACol, ARow, []); - fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); +// fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(lCell); if (uffFont in fmt^.UsedFormattingFields) then fntIndex := fmt^.FontIndex else fntIndex := DEFAULT_FONTINDEX; if (uffTextRotation in fmt^.UsedFormattingFields) then @@ -4670,7 +4671,8 @@ begin if (Result = '') or ((ACell <> nil) and (ACell^.ContentType = cctUTF8String)) then exit; - fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); +// fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(ACell^.Row, ACell^.Col); isRotated := (fmt^.TextRotation <> trHorizontal); isStacked := (fmt^.TextRotation = rtStacked); numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); @@ -5646,8 +5648,10 @@ begin // If it is a date/time format write a date/time cell... if cell <> nil then begin - fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); - if fmt <> nil then nfp := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); +// fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); + fmt := Worksheet.GetPointerToEffectiveCellFormat(cell); + if fmt <> nil then + nfp := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); if (fmt <> nil) and IsDateTimeFormat(nfp) then Worksheet.WriteDateTime(r, c, VarToDateTime(AValue)) else Worksheet.WriteNumber(r, c, AValue); diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas index 27e7158ea..a8b85253e 100644 --- a/components/fpspreadsheet/fpstypes.pas +++ b/components/fpspreadsheet/fpstypes.pas @@ -674,7 +674,7 @@ type Worksheet: Pointer; // Must be cast to TsWorksheet when used (avoids circular unit reference) { Status flags } Flags: TsCellFlags; - { Index of format record in the workbook's FCellFormatList } + { Index of format record in the workbook's CellFormatList } FormatIndex: Integer; { Cell content } UTF8StringValue: String; // Strings cannot be part of a variant record @@ -693,6 +693,57 @@ type {@@ Pointer to a TCell record } PCell = ^TCell; + {@@ Types of row heights + rhtDefault - default row height + rhtAuto - automatically determined row height, depends on font size, + text rotation, rich-text parameters, word-wrap + rhtCustom - user-determined row height (dragging the row header borders in + the grid, or changed by code) } + TsRowHeightType = (rhtDefault, rhtCustom, rhtAuto); + + {@@ Types of column widths + cwtDefault - default column width + cwtCustom - userdefined column width (dragging the column header border + in the grid, or by changed by code) } + TsColWidthtype = (cwtDefault, cwtCustom); + + {@@ The record TRow contains information about a spreadsheet row: + @param Row The index of the row (beginning with 0) + @param Height The height of the row (expressed in the units defined + by the workbook) + @param RowHeightType Specifies whether the row has default, custom, or + automatic height + @param FormatIndex Row default format, index into the workbook's + FCellFormatList + Only rows with non-default height or non-default format have a row record. } + TRow = record + Row: Cardinal; + Height: Single; + RowHeightType: TsRowHeightType; + FormatIndex: Integer; + end; + + {@@ Pointer to a TRow record } + PRow = ^TRow; + + {@@ The record TCol contains information about a spreadsheet column: + @param Col The index of the column (beginning with 0) + @param Width The width of the column (expressed in the units defined + in the workbook) + @param ColWidthType Specifies whether the column has default or custom width + @param FormatIndex Column default format, index into the workbook's + FCellFormatlist + Only columns with non-default width or non-default format have a column record. } + TCol = record + Col: Cardinal; + Width: Single; + ColWidthType: TsColWidthType; + FormatIndex: Integer; + end; + + {@@ Pointer to a TCol record } + PCol = ^TCol; + {@@ Embedded image } TsImage = record Row, Col: Cardinal; // cell for top/left edge of the image (anchor) @@ -725,15 +776,6 @@ type {@@ Array with all possible images in a header or a footer } TsHeaderFooterImages = array[TsHeaderFooterSectionIndex] of TsHeaderFooterImage; -const - {@@ Indexes to be used for the various headers and footers } - HEADER_FOOTER_INDEX_FIRST = 0; - HEADER_FOOTER_INDEX_ODD = 1; - HEADER_FOOTER_INDEX_EVEN = 2; - HEADER_FOOTER_INDEX_ALL = 1; - - -type {@@ Search option } TsSearchOption = (soCompareEntireCell, soMatchCase, soRegularExpr, soAlongRows, soBackward, soWrapDocument, soEntireDocument); @@ -770,18 +812,18 @@ type TsStreamParam = (spClipboard, spWindowsClipboardHTML); TsStreamParams = set of TsStreamParam; - {@@ Types of row heights - rhtDefault - default row height - rhtAuto - automatically determined row height, depends on font size, - text rotation, rich-text parameters, word-wrap - rhtCustom - user-determined row height (dragging the row header borders in - the grid } - TsRowHeightType = (rhtDefault, rhtAuto, rhtCustom); - const RowHeightTypeNames: array[TsRowHeightType] of string = ( 'Default', 'Auto', 'Custom'); + ColWidthTypeNames: array[TsColWidthType] of string = ( + 'Default', 'Custom'); + + {@@ Indexes to be used for the various headers and footers } + HEADER_FOOTER_INDEX_FIRST = 0; + HEADER_FOOTER_INDEX_ODD = 1; + HEADER_FOOTER_INDEX_EVEN = 2; + HEADER_FOOTER_INDEX_ALL = 1; implementation diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index 67f0f7245..2b310065a 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -386,6 +386,7 @@ type procedure AddBuiltinNumFormats; override; procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual; + (* procedure ApplyRichTextFormattingRuns(ACell: PCell; ARuns: TsRichTextFormattingRuns); @@ -1001,6 +1002,7 @@ begin ACell^.FormatIndex := 0; end; end; + (* {@@ ---------------------------------------------------------------------------- Converts the rich-text formatting run data as read from the file to the @@ -1401,19 +1403,37 @@ const var c, c1, c2: Cardinal; w: Word; - colwidth: Double; + xf: Word; + lCol: TCol; + idx: Integer; + fmt: PsCellFormat; begin - // read column start and end index of column range + { Read column start and end index of column range } c1 := WordLEToN(AStream.ReadWord); c2 := WordLEToN(AStream.ReadWord); - // read col width in 1/256 of the width of "0" character + + { Read col width in 1/256 of the width of "0" character } w := WordLEToN(AStream.ReadWord); - // calculate width in workbook units - colwidth := FWorkbook.ConvertUnits(w / 256, suChars, FWorkbook.Units); - // assign width to columns, but only if different from default column width - if not SameValue(colwidth, FWorksheet.ReadDefaultColWidth(FWorkbook.Units), EPS) then + + { Calculate width in workbook units } + lCol.Width := FWorkbook.ConvertUnits(w / 256, suChars, FWorkbook.Units); + if SameValue(lCol.Width, FWorksheet.ReadDefaultColWidth(FWorkbook.Units), EPS) then + lCol.ColWidthType := cwtDefault else + lCol.ColWidthType := cwtCustom; + + { Read xf record index } + xf := WordLEToN(AStream.ReadWord); + idx := FCellFormatList.FindIndexOfID(xf); + if idx > -1 then begin + fmt := FCellFormatList.Items[idx]; + lCol.FormatIndex := FWorkbook.AddCellFormat(fmt^); + end else + lCol.FormatIndex := 0; + + { Assign width and format to columns, but only if different from defaults } + if (lCol.FormatIndex > 0) or (lCol.ColWidthType = cwtCustom) then for c := c1 to c2 do - FWorksheet.WriteColWidth(c, colwidth, FWorkbook.Units); + FWorksheet.WriteColInfo(c, lCol); end; {@@ ---------------------------------------------------------------------------- @@ -2086,33 +2106,56 @@ type end; var rowrec: TRowRecord; - lRow: PRow; + lRow: TRow; h: word; hpts: Single; hdef: Single; isNonDefaultHeight: Boolean; isAutoSizeHeight: Boolean; + hasFormat: Boolean; + flags: DWord; + xf: Word; + idx: Integer; + fmt: PsCellFormat; begin rowrec.RowIndex := 0; // to silence the compiler... AStream.ReadBuffer(rowrec, SizeOf(TRowRecord)); + rowrec.RowIndex := WordLEToN(rowrec.RowIndex); + flags := DWordLEToN(rowrec.Flags); + { Row height } h := WordLEToN(rowrec.Height) and $7FFF; // mask off "custom" bit hpts := FWorkbook.ConvertUnits(TwipsToPts(h), suPoints, FWorkbook.Units); hdef := FWorksheet.ReadDefaultRowHeight(FWorkbook.Units); - isNonDefaultHeight := not SameValue(hpts, hdef, ROWHEIGHT_EPS); - isAutoSizeHeight := WordLEToN(rowrec.Flags) and $00000040 = 0; - // If this bis is set then font size and row height do NOT match, i.e. NO autosize + isAutoSizeHeight := flags and $00000040 = 0; + // If this bit is set then font size and row height do NOT match, i.e. NO autosize + if isAutoSizeHeight then + lRow.RowHeightType := rhtAuto else + lRow.RowHeightType := rhtCustom; + lRow.Height := hpts; + + { Row format } + lRow.FormatIndex := 0; + hasFormat := flags and $00000080 <> 0; + // If this bit is set then the record contains an xf index. + if hasFormat then begin + xf := (flags and $0FFF0000) shr 16; + if xf = 15 then hasFormat := false; + end; + if hasFormat then begin + // Find the format with ID xf + idx := FCellFormatList.FindIndexOfID(xf); + if idx > -1 then begin + fmt := FCellFormatList.Items[idx]; + lRow.FormatIndex := FWorkbook.AddCellFormat(fmt^); + end; + end; // We only create a row record for fpspreadsheet if the row has a - // non-standard height (i.e. different from default row height). - if isNonDefaultHeight then begin - lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex)); - if isAutoSizeHeight then - lRow^.RowHeightType := rhtAuto else - lRow^.RowHeightType := rhtCustom; - lRow^.Height := hpts; - end; + // non-standard height (i.e. different from default row height) or format. + if isNonDefaultHeight or hasFormat then + FWorksheet.WriteRowInfo(rowrec.RowIndex, lRow); end; {@@ ----------------------------------------------------------------------------