FPSpreadsheet: Improved presentation of date axis in chart. Testing to build documentation.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9448 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-09-18 17:57:40 +00:00
parent 712ce264ee
commit 7b43bd5894
11 changed files with 136 additions and 45 deletions

View File

@ -7,5 +7,6 @@
../../source/common/fpsrpn.pas ../../source/common/fpsrpn.pas
../../source/common/fpscurrency.pas ../../source/common/fpscurrency.pas
../../source/common/fpsconditionalformat.pas ../../source/common/fpsconditionalformat.pas
../../source/common/fpschart.pas
../../source/visual/fpspreadsheetctrls.pas ../../source/visual/fpspreadsheetctrls.pas
../../source/visual/fpspreadsheetgrid.pas ../../source/visual/fpspreadsheetgrid.pas

View File

@ -5,12 +5,13 @@ set FMT=chm
echo Downloading wiki... echo Downloading wiki...
wikiget --page=FPSpreadsheet --page=FPSpreadsheet:_Examples --page=FPSpreadsheet:_List_of_formulas --page=RPN_Formulas_in_FPSpreadsheet wikiget --page=FPSpreadsheet --page=FPSpreadsheet:_Examples --page=FPSpreadsheet:_List_of_formulas --page=RPN_Formulas_in_FPSpreadsheet
wikiget --page=FPSpreadsheet:_Chart_Tutorial
wikiget --page=FPSpreadsheet_tutorial:_Writing_a_mini_spreadsheet_application wikiget --page=FPSpreadsheet_tutorial:_Writing_a_mini_spreadsheet_application
wikiget --page=TsWorksheetGrid --page=TsWorksheetChartSource wikiget --page=TsWorksheetGrid --page=TsWorksheetChartSource
echo. echo.
echo Converting wiki to chm... echo Converting wiki to chm...
wikiconvert --format=%FMT% --css=css/wiki.css --root="FPSpreadsheet wiki pages" --title="FPSpreadsheet wiki pages (offline version, created %DATE%)" --chm="..\fpspreadsheet-wiki.chm" wikixml/FPSpreadsheet.s00.xml wikixml/FPSpreadsheet=3A_Examples.s0300.xml wikixml/FPSpreadsheet=3A_List_of_formulas.s03000.xml wikixml/RPN_Formulas_in_FPSpreadsheet.u03g00.xml wikixml/FPSpreadsheet_tutorial=3A_Writing_a_mini_spreadsheet_application.s000c0000000.xml wikixml/TsWorksheetGrid.k08.xml wikiconvert --format=%FMT% --css=css/wiki.css --root="FPSpreadsheet wiki pages" --title="FPSpreadsheet wiki pages (offline version, created %DATE%)" --chm="..\fpspreadsheet-wiki.chm" wikixml/FPSpreadsheet.s00.xml wikixml/FPSpreadsheet=3A_Examples.s0300.xml wikixml/FPSpreadsheet=3A_List_of_formulas.s03000.xml wikixml/RPN_Formulas_in_FPSpreadsheet.u03g00.xml wikixml/FPSpreadsheet_tutorial=3A_Writing_a_mini_spreadsheet_application.s000c0000000.xml wikixml/TsWorksheetGrid.k08.xml wikixml/FPSpreadsheet=3A_Chart_Tutorial.s03100.xml
set FMT= set FMT=

View File

@ -68,11 +68,6 @@
<Debugging> <Debugging>
<DebugInfoType Value="dsDwarf3"/> <DebugInfoType Value="dsDwarf3"/>
</Debugging> </Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking> </Linking>
</CompilerOptions> </CompilerOptions>
<Debugging> <Debugging>

View File

@ -20,7 +20,7 @@ interface
uses uses
Classes, SysUtils, fpimage; Classes, SysUtils, fpimage;
{$IF FPC_FullVersion < 30000} {$IFDEF FPS_NO_RAWBYTESTRING}
{@@ This string type is not re-encoded by FPC. It is a standard type of FPC 3.0+, {@@ This string type is not re-encoded by FPC. It is a standard type of FPC 3.0+,
its declaration must be repeated here in order to keep fpSpreadsheet usable by its declaration must be repeated here in order to keep fpSpreadsheet usable by
older FPC versions. } older FPC versions. }
@ -92,8 +92,8 @@ type
@member LineEnding Specification for the line endings to be written (write-only) @member LineEnding Specification for the line endings to be written (write-only)
@member Delimiter Column delimiter (read/write) @member Delimiter Column delimiter (read/write)
@member QuoteChar Character used for quoting text in special cases (read/write) @member QuoteChar Character used for quoting text in special cases (read/write)
@member QuoteOuterWhiteSpace ...Determines whether cell content beginning/ending with white space will be quoted (write-only) @member QuoteOuterWhiteSpace Determines whether cell content beginning/ending with white space will be quoted (write-only)
@member IgnoreOuterWhiteSpace...Ignores white space before/after cell content (read-only) @member IgnoreOuterWhiteSpace Ignores white space before/after cell content (read-only)
@member Encoding String identifying the endoding of the file, such as 'utf8', 'cp1252' etc (read/write) @member Encoding String identifying the endoding of the file, such as 'utf8', 'cp1252' etc (read/write)
@member DetectContentType Try to convert strings to their content type (read-only) @member DetectContentType Try to convert strings to their content type (read-only)
@member NumberFormat If empty numbers are written like in worksheet, otherwise this format string is applied (write-only) @member NumberFormat If empty numbers are written like in worksheet, otherwise this format string is applied (write-only)

View File

@ -59,7 +59,7 @@ type
procedure ReadChartSeriesLabels(ANode: TDOMNode; ASeries: TsChartSeries); procedure ReadChartSeriesLabels(ANode: TDOMNode; ASeries: TsChartSeries);
procedure ReadChartSeriesMarker(ANode: TDOMNode; ASeries: TsCustomLineSeries); procedure ReadChartSeriesMarker(ANode: TDOMNode; ASeries: TsCustomLineSeries);
procedure ReadChartSeriesProps(ANode: TDOMNode; ASeries: TsChartSeries); procedure ReadChartSeriesProps(ANode: TDOMNode; ASeries: TsChartSeries);
procedure ReadChartSeriesRange(ANode: TDOMNode; ARange: TsChartRange); procedure ReadChartSeriesRange(ANode: TDOMNode; ARange: TsChartRange; var AFormat: String);
procedure ReadChartSeriesTitle(ANode: TDOMNode; ASeries: TsChartSeries); procedure ReadChartSeriesTitle(ANode: TDOMNode; ASeries: TsChartSeries);
procedure ReadChartSeriesTrendLine(ANode: TDOMNode; ASeries: TsChartSeries); procedure ReadChartSeriesTrendLine(ANode: TDOMNode; ASeries: TsChartSeries);
procedure ReadChartStockSeries(ANode: TDOMNode; AChart: TsChart); procedure ReadChartStockSeries(ANode: TDOMNode; AChart: TsChart);
@ -374,6 +374,7 @@ var
n: LongInt; n: LongInt;
x: Single; x: Single;
node: TDOMNode; node: TDOMNode;
srcLinked: Boolean;
begin begin
if ANode = nil then if ANode = nil then
exit; exit;
@ -414,13 +415,22 @@ begin
'c:title': 'c:title':
ReadChartTitle(ANode.FirstChild, AChartAxis.Title); ReadChartTitle(ANode.FirstChild, AChartAxis.Title);
'c:numFmt': 'c:numFmt':
begin
srcLinked := GetAttrValue(ANode, 'sourceLinked') = '1';
if not srcLinked then
begin begin
s := GetAttrValue(ANode, 'formatCode'); s := GetAttrValue(ANode, 'formatCode');
if s = 'm/d/yyyy' then if s = 'm/d/yyyy' then
AChartAxis.LabelFormat := FReader.Workbook.FormatSettings.ShortDateFormat AChartAxis.LabelFormat := FReader.Workbook.FormatSettings.ShortDateFormat
else else
if IsDateTimeFormat(s) then
begin
AChartAxis.DateTime := true;
AChartAxis.LabelFormatDateTime := s;
end else
AChartAxis.LabelFormat := s; AChartAxis.LabelFormat := s;
end; end;
end;
'c:majorTickMark': 'c:majorTickMark':
AChartAxis.MajorTicks := ReadChartAxisTickMarks(ANode); AChartAxis.MajorTicks := ReadChartAxisTickMarks(ANode);
'c:minorTickMark': 'c:minorTickMark':
@ -1806,6 +1816,7 @@ var
val: Double; val: Double;
errorBars: TsChartErrorBars = nil; errorBars: TsChartErrorBars = nil;
part: String = ''; part: String = '';
fmt: String = '';
begin begin
if ANode = nil then if ANode = nil then
exit; exit;
@ -1877,9 +1888,9 @@ begin
errorBars.ValueNeg := val; errorBars.ValueNeg := val;
end; end;
'c:plus': 'c:plus':
ReadChartSeriesRange(node.FirstChild, errorBars.RangePos); ReadChartSeriesRange(node.FirstChild, errorBars.RangePos, fmt);
'c:minus': 'c:minus':
ReadChartSeriesRange(node.FirstChild, errorBars.RangeNeg); ReadChartSeriesRange(node.FirstChild, errorBars.RangeNeg, fmt);
'c:spPr': 'c:spPr':
ReadChartLineProps(node.FirstChild, ASeries.Chart, errorBars.Line); ReadChartLineProps(node.FirstChild, ASeries.Chart, errorBars.Line);
'c:noEndCap': 'c:noEndCap':
@ -2021,9 +2032,10 @@ end;
procedure TsSpreadOOXMLChartReader.ReadChartSeriesProps(ANode: TDOMNode; ASeries: TsChartSeries); procedure TsSpreadOOXMLChartReader.ReadChartSeriesProps(ANode: TDOMNode; ASeries: TsChartSeries);
var var
nodeName, s: String; nodeName, fmt, s: String;
n: Integer; n: Integer;
idx: Integer; idx: Integer;
ax: TsChartAxis;
smooth: Boolean = false; smooth: Boolean = false;
begin begin
if ANode = nil then if ANode = nil then
@ -2040,16 +2052,32 @@ begin
ASeries.Order := n; ASeries.Order := n;
'c:tx': 'c:tx':
ReadChartSeriesTitle(ANode.FirstChild, ASeries); ReadChartSeriesTitle(ANode.FirstChild, ASeries);
'c:cat': 'c:cat': // Category axis
ReadChartSeriesRange(ANode.FirstChild, ASeries.LabelRange); begin
'c:xVal': ReadChartSeriesRange(ANode.FirstChild, ASeries.LabelRange, fmt);
ReadChartSeriesRange(ANode.FirstChild, ASeries.XRange); ax := ASeries.GetXAxis;
'c:val', 'c:yVal': if IsDateTimeFormat(fmt) then
begin
if ax.LabelFormatDateTime = '' then
ax.LabelFormatDateTime := fmt;
end else
begin
if ax.LabelFormat = '' then
ax.LabelFormat := fmt;
end;
end;
'c:xVal': // x value axis
ReadChartSeriesRange(ANode.FirstChild, ASeries.XRange, fmt);
'c:val', // y value axis in categorized series
'c:yVal': // y value axis
if ASeries.YRange.IsEmpty then // TcStockSeries already has read the y range... if ASeries.YRange.IsEmpty then // TcStockSeries already has read the y range...
ReadChartSeriesRange(ANode.FirstChild, ASeries.YRange); begin
ReadChartSeriesRange(ANode.FirstChild, ASeries.YRange, fmt);
ASeries.LabelFormat := fmt;
end;
'c:bubbleSize': 'c:bubbleSize':
if ASeries is TsBubbleSeries then if ASeries is TsBubbleSeries then
ReadChartSeriesRange(ANode.FirstChild, TsBubbleSeries(ASeries).BubbleRange); ReadChartSeriesRange(ANode.FirstChild, TsBubbleSeries(ASeries).BubbleRange, fmt);
'c:bubble3D': 'c:bubble3D':
; ;
'c:spPr': 'c:spPr':
@ -2084,14 +2112,18 @@ end;
@@param ANode First child of a <c:val>, <c:yval> or <c:cat> node below <c:ser>. @@param ANode First child of a <c:val>, <c:yval> or <c:cat> node below <c:ser>.
@@param ARange Cell range to which the range parameters will be assigned. @@param ARange Cell range to which the range parameters will be assigned.
@@param AFormat Numberformat string
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadOOXMLChartReader.ReadChartSeriesRange(ANode: TDOMNode; ARange: TsChartRange); procedure TsSpreadOOXMLChartReader.ReadChartSeriesRange(ANode: TDOMNode;
ARange: TsChartRange; var AFormat: String);
var var
node, child: TDomNode;
nodeName, s: String; nodeName, s: String;
sheet1, sheet2: String; sheet1, sheet2: String;
r1, c1, r2, c2: Cardinal; r1, c1, r2, c2: Cardinal;
flags: TsRelFlags; flags: TsRelFlags;
begin begin
AFormat := '';
if ANode = nil then if ANode = nil then
exit; exit;
while Assigned(ANode) do while Assigned(ANode) do
@ -2099,6 +2131,38 @@ begin
nodeName := ANode.NodeName; nodeName := ANode.NodeName;
if (nodeName = 'c:strRef') or (nodeName = 'c:numRef') then if (nodeName = 'c:strRef') or (nodeName = 'c:numRef') then
begin begin
node := ANode.FirstChild;
while Assigned(node) do
begin
nodeName := node.NodeName;
case nodeName of
'c:f':
begin
s := GetNodeValue(node);
if ParseCellRangeString(s, sheet1, sheet2, r1, c1, r2, c2, flags) then
begin
if sheet2 = '' then sheet2 := sheet1;
ARange.Sheet1 := sheet1;
ARange.Sheet2 := sheet2;
ARange.Row1 := r1;
ARange.Col1 := c1;
ARange.Row2 := r2;
ARange.Col2 := c2;
end;
end;
'c:numCache':
begin
child := node.FindNode('c:formatCode');
if Assigned(child) then
AFormat := GetNodeValue(child);
end;
end;
node := node.NextSibling;
end;
end;
ANode := ANode.NextSibling;
(*
ANode := ANode.FindNode('c:f'); ANode := ANode.FindNode('c:f');
if ANode <> nil then if ANode <> nil then
begin begin
@ -2117,6 +2181,7 @@ begin
end; end;
end; end;
ANode := ANode.NextSibling; ANode := ANode.NextSibling;
*)
end; end;
end; end;
@ -2234,7 +2299,7 @@ procedure TsSpreadOOXMLChartReader.ReadChartStockSeries(ANode: TDOMNode;
AChart: TsChart); AChart: TsChart);
var var
ser: TsStockSeries; ser: TsStockSeries;
nodeName: String; nodeName, fmt: String;
sernode, child: TDOMNode; sernode, child: TDOMNode;
begin begin
if ANode = nil then if ANode = nil then
@ -2266,14 +2331,14 @@ begin
} }
'c:val': 'c:val':
if ser.CloseRange.IsEmpty then if ser.CloseRange.IsEmpty then
ReadChartSeriesRange(child.FirstChild, ser.CloseRange) ReadChartSeriesRange(child.FirstChild, ser.CloseRange, fmt)
else if ser.LowRange.IsEmpty then else if ser.LowRange.IsEmpty then
ReadChartSeriesRange(child.FirstChild, ser.LowRange) ReadChartSeriesRange(child.FirstChild, ser.LowRange, fmt)
else if ser.HighRange.IsEmpty then else if ser.HighRange.IsEmpty then
ReadChartSeriesRange(child.FirstChild, ser.HighRange) ReadChartSeriesRange(child.FirstChild, ser.HighRange, fmt)
else if ser.OpenRange.IsEmpty then else if ser.OpenRange.IsEmpty then
begin begin
ReadChartSeriesRange(child.FirstChild, ser.OpenRange); ReadChartSeriesRange(child.FirstChild, ser.OpenRange, fmt);
ser.CandleStick := true; ser.CandleStick := true;
end; end;
end; end;

View File

@ -25,6 +25,15 @@
{ The next defines activate code duplicated from new compiler versions in case { The next defines activate code duplicated from new compiler versions in case
an old compiler is used. } an old compiler is used. }
{ Activate the following define if your Lazarus version is older than v1.8 }
{.$DEFINE LCL_FullVersion_LT_v180}
{ Activate the following define if your Lazarus version is older than v1.9 }
{.$DEFINE LCL_FullVersion_LT_v190}
{ Activate the following define if your Lazarus version is older than v2.0 }
{.$DEFINE LCL_FullVersion_LT_v200}
{ fpspreadsheet requires the function VarIsBool which was introduced by { fpspreadsheet requires the function VarIsBool which was introduced by
fpc 2.6.4. If an older FPC versions is used define FPS_VARISBOOL. Keep fpc 2.6.4. If an older FPC versions is used define FPS_VARISBOOL. Keep
undefined for the current FPC version. } undefined for the current FPC version. }
@ -66,7 +75,22 @@
e.g. before v3.0 } e.g. before v3.0 }
{.$DEFINE FPS_NO_STRING_SPLIT} {.$DEFINE FPS_NO_STRING_SPLIT}
{ FPC versions before 3.0 did not support TRawByteString.
Enable the define FPS_NO_RAWBYTESTRING here if this is the case. }
{.$DEFINE FPS_NO_RAWBYTESTRING}
{ Very old FPC versions do not contain zip support in the unit zipper, and { Very old FPC versions do not contain zip support in the unit zipper, and
until v3.3 zipper did not read pass-word protected ods files correctly. until v3.3 zipper did not read pass-word protected ods files correctly.
Therefore, the following define must be activated if FPC is v3.3 or older. } Therefore, the following define must be activated if FPC is v3.3 or older. }
{$DEFINE FPS_PATCHED_ZIPPER} {$DEFINE FPS_PATCHED_ZIPPER}
// Fix dependent defines
{$IFDEF LCL_FULLVERSION_LT_200}
{$DEFINE LCL_FULLVERSION_LT_190}
{$ENDIF}
{$IFDEF LCL_FULLVERSION_LT_190}
{$DEFINE LCL_FULLVERSION_LT_180}
{$ENDIF}

View File

@ -688,11 +688,17 @@ begin
if cell <> nil then if cell <> nil then
case cell^.ContentType of case cell^.ContentType of
cctUTF8String, cctDateTime: // !!! Simplification here: we do not support real date values cctUTF8String:
begin begin
ANumber := APointIndex; ANumber := APointIndex;
AText := FWorksheets[ARangeIndex, AListIndex].ReadAsText(cell); AText := FWorksheets[ARangeIndex, AListIndex].ReadAsText(cell);
end; end;
cctDateTime:
begin
if not FWorksheets[ARangeIndex, AListIndex].ReadAsDateTime(cell, ANumber) then
ANumber := APointIndex;
AText := FWorksheets[ARangeIndex, AListIndex].ReadAsText(cell);
end;
else else
ANumber := FWorksheets[ARangeIndex, AListIndex].ReadAsNumber(cell); ANumber := FWorksheets[ARangeIndex, AListIndex].ReadAsNumber(cell);
AText := ''; AText := '';
@ -2385,7 +2391,7 @@ begin
FChart.BottomAxis.Marks.Style := smsLabel; FChart.BottomAxis.Marks.Style := smsLabel;
end; end;
end; end;
(*
// Date/time? // Date/time?
if AWorkbookChart.XAxis.DateTime then if AWorkbookChart.XAxis.DateTime then
begin begin
@ -2398,7 +2404,6 @@ begin
DateTimeFormat := AWorkbookChart.XAxis.LabelFormat; DateTimeFormat := AWorkbookChart.XAxis.LabelFormat;
end; end;
end; end;
*)
end; end;
procedure TsWorkbookChartLink.UpdateChartBackground(AWorkbookChart: TsChart); procedure TsWorkbookChartLink.UpdateChartBackground(AWorkbookChart: TsChart);

View File

@ -702,7 +702,7 @@ type
function SpreadsheetFormatInClipboard: Boolean; function SpreadsheetFormatInClipboard: Boolean;
{$IF LCL_FullVersion < 1080000} {$IFDEF LCL_FULLVERSION_LT_180}
function ScalePPI(ALength: Integer): Integer; function ScalePPI(ALength: Integer): Integer;
{$IFEND} {$IFEND}
@ -741,7 +741,7 @@ begin
end; end;
{$IF LCL_FullVersion < 1080000} {$IFDEF LCL_FullVersion_LT_180}
function ScalePPI(ALength: Integer): Integer; function ScalePPI(ALength: Integer): Integer;
begin begin
Result := MulDiv(ALength, Screen.PixelsPerInch, 96); Result := MulDiv(ALength, Screen.PixelsPerInch, 96);

View File

@ -330,7 +330,7 @@ type
const ACellRect: TGridRect): Boolean; const ACellRect: TGridRect): Boolean;
function MouseOnHeader(X, Y: Integer): Boolean; function MouseOnHeader(X, Y: Integer): Boolean;
procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override; procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
{$IF LCL_FullVersion >= 1090000} {$IFNDEF LCL_FullVersion_LT_190000}
function MoveNextSelectable(Relative: Boolean; DCol, DRow: Integer): Boolean; override; function MoveNextSelectable(Relative: Boolean; DCol, DRow: Integer): Boolean; override;
{$ENDIF} {$ENDIF}
procedure MoveSelection; override; procedure MoveSelection; override;
@ -596,10 +596,10 @@ type
defined by the rectangle. } defined by the rectangle. }
property TextRotations[ALeft, ATop, ARight, ABottom: Integer]: TsTextRotation property TextRotations[ALeft, ATop, ARight, ABottom: Integer]: TsTextRotation
read GetTextRotations write SetTextRotations; read GetTextRotations write SetTextRotations;
{$IF LCL_FullVersion >= 1080000} {$IFNDEF LCL_FullVersion_LT_180}
{@@ Pixel coordinates of the top-left corner of the grid's cell area} {@@ Pixel coordinates of the top-left corner of the grid's cell area}
property TopLeftPx: TPoint read GetPxTopLeft; property TopLeftPx: TPoint read GetPxTopLeft;
{$IFEND} {$ENDIF}
{@@ Parameter for vertical text alignment in the cell at column ACol and row ARow. } {@@ Parameter for vertical text alignment in the cell at column ACol and row ARow. }
property VertAlignment[ACol, ARow: Integer]: TsVertAlignment property VertAlignment[ACol, ARow: Integer]: TsVertAlignment
read GetVertAlignment write SetVertAlignment; read GetVertAlignment write SetVertAlignment;
@ -2771,11 +2771,11 @@ begin
Canvas.Brush.Color := clRed; Canvas.Brush.Color := clRed;
Canvas.Brush.Style := bsSolid; Canvas.Brush.Style := bsSolid;
Canvas.Pen.Style := psClear; Canvas.Pen.Style := psClear;
{$IF LCL_FullVersion >= 1080000} {$IFDEF LCL_FULLVERSION_LT_180}
commentSize := Scale96ToFont(COMMENT_SIZE);
{$ELSE}
commentSize := ScalePPI(COMMENT_SIZE); commentSize := ScalePPI(COMMENT_SIZE);
{$IFEND} {$ELSE}
commentSize := Scale96ToFont(COMMENT_SIZE);
{$ENDIF}
if IsRightToLeft then if IsRightToLeft then
begin begin
P[0] := Point(ARect.Left, ARect.Top); P[0] := Point(ARect.Left, ARect.Top);
@ -5256,7 +5256,7 @@ begin
Refresh; Refresh;
end; end;
{$IF LCL_FullVersion >= 1090000} {$IFNDEF LCL_FULLVERSION_LT_v190} // Supported by Laz v1.9+
function TsCustomWorksheetGrid.MoveNextSelectable(Relative: Boolean; DCol, DRow: Integer function TsCustomWorksheetGrid.MoveNextSelectable(Relative: Boolean; DCol, DRow: Integer
): Boolean; ): Boolean;
var var