{ Included by fpspreadsheet.pas } { Code for number format } {==============================================================================} { TsWorksheet code for number format } {==============================================================================} {@@ ---------------------------------------------------------------------------- Determines some number format attributes (decimal places, currency symbol) of a cell @param ACell Pointer to the cell under investigation @param ADecimals Number of decimal places that can be extracted from the formatting string, e.g. in case of '0.000' this would be 3. @param ACurrencySymbol String representing the currency symbol extracted from the formatting string. @return true if the the format string could be analyzed successfully, false if not -------------------------------------------------------------------------------} function TsWorksheet.GetNumberFormatAttributes(ACell: PCell; out ADecimals: byte; out ACurrencySymbol: String): Boolean; var parser: TsNumFormatParser; nf: TsNumberFormat; nfs: String; begin Result := false; if ACell <> nil then begin ReadNumFormat(ACell, nf, nfs); parser := TsNumFormatParser.Create(nfs, FWorkbook.FormatSettings); try if parser.Status = psOK then begin nf := parser.NumFormat; if (nf = nfGeneral) and (ACell^.ContentType = cctNumber) then begin ADecimals := GetDisplayedDecimals(ACell); ACurrencySymbol := ''; end else if IsDateTimeFormat(nf) then begin ADecimals := 2; ACurrencySymbol := '?'; end else begin ADecimals := parser.Decimals; ACurrencySymbol := parser.CurrencySymbol; end; Result := true; end; finally parser.Free; end; end; end; {@@ ---------------------------------------------------------------------------- Returns the number format type and format string used in a specific cell -------------------------------------------------------------------------------} procedure TsWorksheet.ReadNumFormat(ACell: PCell; out ANumFormat: TsNumberFormat; out ANumFormatStr: String); var fmt: PsCellFormat; numFmt: TsNumFormatParams; begin ANumFormat := nfGeneral; ANumFormatStr := ''; if ACell <> nil then begin fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); if (uffNumberFormat in fmt^.UsedFormattingFields) then begin numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); if numFmt <> nil then begin ANumFormat := numFmt.NumFormat; ANumFormatStr := numFmt.NumFormatStr; end else begin ANumFormat := nfGeneral; ANumFormatStr := ''; end; end; end; end; {@@ ---------------------------------------------------------------------------- Adds a date/time format to the formatting of a cell @param ARow The row of the cell @param ACol The column of the cell @param ANumFormat Identifier of the format to be applied (nfXXXX constant) @param ANumFormatString Optional string of formatting codes. Is only considered if ANumberFormat is nfCustom. @return Pointer to the cell @see TsNumberFormat -------------------------------------------------------------------------------} function TsWorksheet.WriteDateTimeFormat(ARow, ACol: Cardinal; ANumFormat: TsNumberFormat; const ANumFormatString: String = ''): PCell; begin Result := GetCell(ARow, ACol); WriteDateTimeFormat(Result, ANumFormat, ANumFormatString); end; {@@ ---------------------------------------------------------------------------- Adds a date/time format to the formatting of a cell @param ACell Pointer to the cell considered @param ANumFormat Identifier of the format to be applied (nxXXXX constant) @param ANumFormatString optional string of formatting codes. Is only considered if ANumberFormat is nfCustom. @see TsNumberFormat -------------------------------------------------------------------------------} procedure TsWorksheet.WriteDateTimeFormat(ACell: PCell; ANumFormat: TsNumberFormat; const ANumFormatString: String = ''); var fmt: TsCellFormat; nfs: String; nfp: TsNumFormatParams; isTextFmt, wasTextFmt: Boolean; oldVal: String; begin if ACell = nil then exit; if not ((ANumFormat in [nfGeneral, nfCustom]) or IsDateTimeFormat(ANumFormat)) then raise EFPSpreadsheet.Create('WriteDateTimeFormat can only be called with date/time formats.'); isTextFmt := false; wasTextFmt := false; fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt.NumberFormat := ANumFormat; if (ANumFormat <> nfGeneral) then begin nfp := Workbook.GetNumberFormat(fmt.NumberFormatIndex); wasTextFmt := IsTextFormat(nfp); oldval := ReadAsText(ACell); Include(fmt.UsedFormattingFields, uffNumberFormat); if (ANumFormatString = '') then nfs := BuildDateTimeFormatString(ANumFormat, Workbook.FormatSettings) else nfs := ANumFormatString; isTextFmt := (nfs = '@'); end else begin Exclude(fmt.UsedFormattingFields, uffNumberFormat); fmt.NumberFormatStr := ''; end; fmt.NumberFormat := ANumFormat; fmt.NumberFormatStr := nfs; fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs); ACell^.FormatIndex := FWorkbook.AddCellFormat(fmt); if isTextFmt then WriteText(ACell, oldval) else if wasTextFmt then WriteCellValueAsString(ACell, ACell^.UTF8StringValue); ChangedCell(ACell^.Row, ACell^.Col); end; {@@ ---------------------------------------------------------------------------- Formats the number in a cell to show a given count of decimal places. Is ignored for non-decimal formats (such as most date/time formats). @param ARow Row indows of the cell considered @param ACol Column indows of the cell considered @param ADecimals Number of decimal places to be displayed @return Pointer to the cell @see TsNumberFormat -------------------------------------------------------------------------------} function TsWorksheet.WriteDecimals(ARow, ACol: Cardinal; ADecimals: Byte): PCell; begin Result := FindCell(ARow, ACol); WriteDecimals(Result, ADecimals); end; {@@ ---------------------------------------------------------------------------- Formats the number in a cell to show a given count of decimal places. Is ignored for non-decimal formats (such as most date/time formats). @param ACell Pointer to the cell considered @param ADecimals Number of decimal places to be displayed @see TsNumberFormat -------------------------------------------------------------------------------} procedure TsWorksheet.WriteDecimals(ACell: PCell; ADecimals: Byte); var parser: TsNumFormatParser; fmt: TsCellFormat; numFmt: TsNumFormatParams; numFmtStr: String; begin if (ACell = nil) or (ACell^.ContentType <> cctNumber) then exit; fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); numFmt := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex); if numFmt <> nil then numFmtStr := numFmt.NumFormatStr else numFmtStr := '0.00'; parser := TsNumFormatParser.Create(numFmtStr, Workbook.FormatSettings); try parser.Decimals := ADecimals; numFmtStr := parser.FormatString; fmt.NumberFormatIndex := Workbook.AddNumberFormat(numFmtStr); Include(fmt.UsedFormattingFields, uffNumberFormat); ACell^.FormatIndex := Workbook.AddCellFormat(fmt); ChangedCell(ACell^.Row, ACell^.Col); finally parser.Free; end; end; {@@ ---------------------------------------------------------------------------- Formats a number as a fraction @param ARow Row index of the cell @param ACol Column index of the cell @param ANumFormat Identifier of the format to be applied. Must be either nfFraction or nfMixedFraction @param ANumeratorDigts Count of numerator digits @param ADenominatorDigits Count of denominator digits @return Pointer to the cell @see TsNumberFormat -------------------------------------------------------------------------------} function TsWorksheet.WriteFractionFormat(ARow, ACol: Cardinal; AMixedFraction: Boolean; ANumeratorDigits, ADenominatorDigits: Integer): PCell; begin Result := GetCell(ARow, ACol); WriteFractionFormat(Result, AMixedFraction, ANumeratorDigits, ADenominatorDigits); end; {@@ ---------------------------------------------------------------------------- Formats a number as a fraction @param ACell Pointer to the cell to be formatted @param ANumFormat Identifier of the format to be applied. Must be either nfFraction or nfMixedFraction @param ANumeratorDigts Count of numerator digits @param ADenominatorDigits Count of denominator digits @see TsNumberFormat -------------------------------------------------------------------------------} procedure TsWorksheet.WriteFractionFormat(ACell: PCell; AMixedFraction: Boolean; ANumeratorDigits, ADenominatorDigits: Integer); var fmt: TsCellFormat; nfs: String; begin if ACell = nil then exit; fmt := Workbook.GetCellFormat(ACell^.FormatIndex); nfs := BuildFractionFormatString(AMixedFraction, ANumeratorDigits, ADenominatorDigits); fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs); Include(fmt.UsedFormattingFields, uffNumberFormat); ACell^.FormatIndex := Workbook.AddCellFormat(fmt); ChangedCell(ACell^.Row, ACell^.Col); end; {@@ ---------------------------------------------------------------------------- Adds a number format to the formatting of a cell @param ARow The row of the cell @param ACol The column of the cell @param ANumFormat Identifier of the format to be applied @param ADecimals Number of decimal places @param ACurrencySymbol optional currency symbol in case of nfCurrency @param APosCurrFormat optional identifier for positive currencies @param ANegCurrFormat optional identifier for negative currencies @return Pointer to the cell @see TsNumberFormat -------------------------------------------------------------------------------} function TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal; ANumFormat: TsNumberFormat; ADecimals: Integer; ACurrencySymbol: String = ''; APosCurrFormat: Integer = -1; ANegCurrFormat: Integer = -1): PCell; begin Result := GetCell(ARow, ACol); WriteNumberFormat(Result, ANumFormat, ADecimals, ACurrencySymbol, APosCurrFormat, ANegCurrFormat); end; {@@ ---------------------------------------------------------------------------- Adds a number format to the formatting of a cell @param ARow The row of the cell @param ACol The column of the cell @param ANumFormat Identifier of the format to be applied @param ADecimals Number of decimal places @param ACurrencySymbol optional currency symbol in case of nfCurrency @param APosCurrFormat optional identifier for positive currencies @param ANegCurrFormat optional identifier for negative currencies @see TsNumberFormat -------------------------------------------------------------------------------} procedure TsWorksheet.WriteNumberFormat(ACell: PCell; ANumFormat: TsNumberFormat; ADecimals: Integer; ACurrencySymbol: String = ''; APosCurrFormat: Integer = -1; ANegCurrFormat: Integer = -1); var fmt: TsCellFormat; fmtStr: String; nfp: TsNumFormatParams; wasTextFmt: Boolean; begin if ACell = nil then exit; wasTextFmt := false; fmt := Workbook.GetCellFormat(ACell^.FormatIndex); fmt.NumberFormat := ANumFormat; if ANumFormat <> nfGeneral then begin nfp := Workbook.GetNumberFormat(fmt.NumberFormatIndex); wasTextFmt := IsTextFormat(nfp); Include(fmt.UsedFormattingFields, uffNumberFormat); if IsCurrencyFormat(ANumFormat) then begin RegisterCurrency(ACurrencySymbol); fmtStr := BuildCurrencyFormatString(ANumFormat, Workbook.FormatSettings, ADecimals, APosCurrFormat, ANegCurrFormat, ACurrencySymbol); end else fmtStr := BuildNumberFormatString(ANumFormat, Workbook.FormatSettings, ADecimals); fmt.NumberFormatIndex := Workbook.AddNumberFormat(fmtStr); end else begin Exclude(fmt.UsedFormattingFields, uffNumberFormat); fmt.NumberFormatIndex := -1; end; ACell^.FormatIndex := Workbook.AddCellFormat(fmt); if wasTextFmt then WriteCellValueAsString(ACell, ACell^.UTF8StringValue); ChangedCell(ACell^.Row, ACell^.Col); end; {@@ ---------------------------------------------------------------------------- Adds a number format to the formatting of a cell @param ARow The row of the cell @param ACol The column of the cell @param ANumFormat Identifier of the format to be applied @param ANumFormatString Optional string of formatting codes. Is only considered if ANumberFormat is nfCustom. @return Pointer to the cell @see TsNumberFormat -------------------------------------------------------------------------------} function TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal; ANumFormat: TsNumberFormat; const ANumFormatString: String = ''): PCell; begin Result := GetCell(ARow, ACol); WriteNumberFormat(Result, ANumFormat, ANumFormatString); end; {@@ ---------------------------------------------------------------------------- Adds a number format to the formatting of a cell @param ACell Pointer to the cell considered @param ANumFormat Identifier of the format to be applied @param ANumFormatString Optional string of formatting codes. Is only considered if ANumberFormat is nfCustom. @see TsNumberFormat -------------------------------------------------------------------------------} procedure TsWorksheet.WriteNumberFormat(ACell: PCell; ANumFormat: TsNumberFormat; const ANumFormatString: String = ''); var fmt: TsCellFormat; fmtStr: String; nfp: TsNumFormatParams; oldval: String; isTextFmt, wasTextFmt: Boolean; begin if ACell = nil then exit; isTextFmt := false; wasTextFmt := false; fmt := Workbook.GetCellFormat(ACell^.FormatIndex); if ANumFormat <> nfGeneral then begin nfp := Workbook.GetNumberFormat(fmt.NumberFormatIndex); wasTextFmt := IsTextFormat(nfp); oldval := ReadAsText(ACell); Include(fmt.UsedFormattingFields, uffNumberFormat); if (ANumFormatString = '') then fmtStr := BuildNumberFormatString(ANumFormat, Workbook.FormatSettings) else fmtStr := ANumFormatString; isTextFmt := (fmtstr = '@'); fmt.NumberFormatIndex := Workbook.AddNumberFormat(fmtStr); end else begin Exclude(fmt.UsedFormattingFields, uffNumberFormat); fmt.NumberFormatIndex := -1; end; ACell^.FormatIndex := Workbook.AddCellFormat(fmt); if isTextFmt then WriteText(ACell, oldval) else if wasTextFmt then WriteCellValueAsString(ACell, ACell^.UTF8StringValue); ChangedCell(ACell^.Row, ACell^.Col); end; {==============================================================================} { TsWorkbook code for number format } {==============================================================================} {@@ ---------------------------------------------------------------------------- Adds a number format to the internal list. Returns the list index if already present, or creates a new format item and returns its index. -------------------------------------------------------------------------------} function TsWorkbook.AddNumberFormat(AFormatStr: String): Integer; begin if AFormatStr = '' then Result := -1 // General number format is not stored else Result := TsNumFormatList(FNumFormatList).AddFormat(AFormatStr); end; {@@ ---------------------------------------------------------------------------- Returns the parameters of the number format stored in the NumFormatList at the specified index. "General" number format is returned as nil. -------------------------------------------------------------------------------} function TsWorkbook.GetNumberFormat(AIndex: Integer): TsNumFormatParams; begin if (AIndex >= 0) and (AIndex < FNumFormatList.Count) then Result := TsNumFormatParams(FNumFormatList.Items[AIndex]) else Result := nil; end; {@@ ---------------------------------------------------------------------------- Returns the count of number format records stored in the NumFormatList -------------------------------------------------------------------------------} function TsWorkbook.GetNumberFormatCount: Integer; begin Result := FNumFormatList.Count; end; {@@ ---------------------------------------------------------------------------- Removes all numberformats Use carefully! -------------------------------------------------------------------------------} procedure TsWorkbook.RemoveAllNumberFormats; var i: Integer; nfp: TsNumFormatParams; begin for i:= FEmbeddedObjList.Count-1 downto 0 do begin nfp := TsNumFormatParams(FNumFormatList[i]); FNumFormatList.Delete(i); nfp.Free; end; end;