fpspreadsheet: Reading of horizontal/vertical text alignment from ods files. Have to implement column styles to all formats correctly.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3113 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-28 16:23:50 +00:00
parent 3565623f83
commit e8f2524a91
2 changed files with 224 additions and 80 deletions

View File

@ -58,12 +58,17 @@ type
TsSpreadOpenDocReader = class(TsCustomSpreadReader)
private
FStyleList: TFPList;
FCellStyleList: TFPList;
FColumnStyleList: TFPList;
FColumnList: TFPList;
FDateMode: TDateMode;
// Applies a style to a cell
procedure ApplyStyleToCell(ARow, ACol: Cardinal; AStyleName: String);
// Searches a style by its name in the StyleList
function FindStyleByName(AStyleName: String): integer;
function FindCellStyleByName(AStyleName: String): integer;
// Searches a column style by its column index or its name in the StyleList
function FindColumnByCol(AColIndex: Integer): Integer;
function FindColStyleByName(AStyleName: String): integer;
// Gets value for the specified attribute. Returns empty string if attribute
// not found.
function GetAttrValue(ANode : TDOMNode; AAttrName : string) : string;
@ -189,8 +194,8 @@ const
('0.002cm', '2pt', '0.002cm', '0.002cm', '3pt', '0.039cm', '0.002cm');
type
{ Style items relevant to FPSpreadsheet. Stored in the StylesList of the reader. }
TStyleData = class
{ Cell style items relevant to FPSpreadsheet. Stored in the CellStyleList of the reader. }
TCellStyleData = class
public
Name: String;
FontIndex: Integer;
@ -204,6 +209,21 @@ type
BackgroundColor: TsColor;
end;
{ Column style items stored in ColStyleList of the reader }
TColumnStyleData = class
public
Name: String;
ColWidth: Double;
end;
{ Column data items stored in the ColList of the reader }
TColumnData = class
public
Col: Integer;
ColStyleIndex: integer; // index into FColumnStyleList of reader
DefaultCellStyleIndex: Integer; // Index of default cell style in FCellStyleList of reader
end;
{ TsSpreadOpenDocNumFormatList }
@ -218,7 +238,9 @@ end;
constructor TsSpreadOpenDocReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
FStyleList := TFPList.Create;
FCellStyleList := TFPList.Create;
FColumnStyleList := TFPList.Create;
FColumnList := TFPList.Create;
// Set up the default palette in order to have the default color names correct.
Workbook.UseDefaultPalette;
// Initial base date in case it won't be read from file
@ -229,8 +251,15 @@ destructor TsSpreadOpenDocReader.Destroy;
var
j: integer;
begin
for j := FStyleList.Count-1 downto 0 do TObject(FStyleList[j]).Free;
FStyleList.Free;
for j := FColumnList.Count-1 downto 0 do TObject(FColumnList[j]).Free;
FColumnList.Free;
for j := FColumnStyleList.Count-1 downto 0 do TObject(FColumnStyleList[j]).Free;
FColumnStyleList.Free;
for j := FCellStyleList.Count-1 downto 0 do TObject(FCellStyleList[j]).Free;
FCellStyleList.Free;
inherited Destroy;
end;
@ -239,73 +268,92 @@ procedure TsSpreadOpenDocReader.ApplyStyleToCell(ARow, ACol: Cardinal;
AStyleName: String);
var
cell: PCell;
styleData: TStyleData;
styleData: TCellStyleData;
styleIndex: Integer;
numFmtData: TsNumFormatData;
i: Integer;
begin
cell := FWorksheet.GetCell(ARow, ACol);
if Assigned(cell) then begin
styleIndex := FindStyleByName(AStyleName);
if styleIndex = -1 then
if not Assigned(cell) then
exit;
// Is there a style attached to the cell?
styleIndex := -1;
if AStyleName <> '' then
styleIndex := FindCellStyleByName(AStyleName);
if (styleIndex = -1) then begin
// No - look for the style attached to the column of the cell and
// find the cell style by the DefaultCellStyleIndex stored in the column list.
i := FindColumnByCol(ACol);
if i = -1 then
exit;
styleData := TStyleData(FStyleList[styleIndex]);
// Font
{
if style.FontIndex = 1 then
Include(cell^.UsedFormattingFields, uffBold)
else
if XFData.FontIndex > 1 then
Include(cell^.UsedFormattingFields, uffFont);
cell^.FontIndex := styleData.FontIndex;
}
// Alignment
cell^.HorAlignment := styleData.HorAlignment;
cell^.VertAlignment := styleData.VertAlignment;
// Word wrap
if styleData.WordWrap then
Include(cell^.UsedFormattingFields, uffWordWrap)
else
Exclude(cell^.UsedFormattingFields, uffWordWrap);
// Text rotation
if styleData.TextRotation > trHorizontal then
Include(cell^.UsedFormattingFields, uffTextRotation)
else
Exclude(cell^.UsedFormattingFields, uffTextRotation);
cell^.TextRotation := styledata.TextRotation;
// Borders
cell^.BorderStyles := styleData.BorderStyles;
if styleData.Borders <> [] then begin
Include(cell^.UsedFormattingFields, uffBorder);
cell^.Border := styleData.Borders;
end else
Exclude(cell^.UsedFormattingFields, uffBorder);
// Background color
if styleData.BackgroundColor <> scNotDefined then begin
Include(cell^.UsedFormattingFields, uffBackgroundColor);
cell^.BackgroundColor := styleData.BackgroundColor;
end;
// Number format
if styleData.NumFormatIndex > -1 then
if cell^.ContentType = cctNumber then begin
numFmtData := NumFormatList[styleData.NumFormatIndex];
if numFmtData <> nil then begin
Include(cell^.UsedFormattingFields, uffNumberFormat);
cell^.NumberFormat := numFmtData.NumFormat;
cell^.NumberFormatStr := numFmtData.FormatString;
cell^.Decimals := numFmtData.Decimals;
cell^.CurrencySymbol := numFmtData.CurrencySymbol;
end;
end;
styleIndex := TColumnData(FColumnList[i]).DefaultCellStyleIndex;
end;
styleData := TCellStyleData(FCellStyleList[styleIndex]);
// Now copy all style parameters from the styleData to the cell.
// Font
{
if style.FontIndex = 1 then
Include(cell^.UsedFormattingFields, uffBold)
else
if XFData.FontIndex > 1 then
Include(cell^.UsedFormattingFields, uffFont);
cell^.FontIndex := styleData.FontIndex;
}
// Alignment
cell^.HorAlignment := styleData.HorAlignment;
cell^.VertAlignment := styleData.VertAlignment;
// Word wrap
if styleData.WordWrap then
Include(cell^.UsedFormattingFields, uffWordWrap)
else
Exclude(cell^.UsedFormattingFields, uffWordWrap);
// Text rotation
if styleData.TextRotation > trHorizontal then
Include(cell^.UsedFormattingFields, uffTextRotation)
else
Exclude(cell^.UsedFormattingFields, uffTextRotation);
cell^.TextRotation := styledata.TextRotation;
// Text alignment
if styleData.HorAlignment <> haDefault then begin
Include(cell^.UsedFormattingFields, uffHorAlign);
cell^.HorAlignment := styleData.HorAlignment;
end else
Exclude(cell^.UsedFormattingFields, uffHorAlign);
if styleData.VertAlignment <> vaDefault then begin
Include(cell^.UsedFormattingFields, uffVertAlign);
cell^.VertAlignment := styleData.VertAlignment;
end else
Exclude(cell^.UsedFormattingFields, uffVertAlign);
// Borders
cell^.BorderStyles := styleData.BorderStyles;
if styleData.Borders <> [] then begin
Include(cell^.UsedFormattingFields, uffBorder);
cell^.Border := styleData.Borders;
end else
Exclude(cell^.UsedFormattingFields, uffBorder);
// Background color
if styleData.BackgroundColor <> scNotDefined then begin
Include(cell^.UsedFormattingFields, uffBackgroundColor);
cell^.BackgroundColor := styleData.BackgroundColor;
end;
// Number format
if styleData.NumFormatIndex > -1 then
if cell^.ContentType = cctNumber then begin
numFmtData := NumFormatList[styleData.NumFormatIndex];
if numFmtData <> nil then begin
Include(cell^.UsedFormattingFields, uffNumberFormat);
cell^.NumberFormat := numFmtData.NumFormat;
cell^.NumberFormatStr := numFmtData.FormatString;
cell^.Decimals := numFmtData.Decimals;
cell^.CurrencySymbol := numFmtData.CurrencySymbol;
end;
end;
end;
{ Creates the correct version of the number format list
@ -316,15 +364,31 @@ begin
FNumFormatList := TsSpreadOpenDocNumFormatList.Create(Workbook);
end;
function TsSpreadOpenDocReader.FindStyleByName(AStyleName: String): Integer;
function TsSpreadOpenDocReader.FindCellStyleByName(AStyleName: String): Integer;
begin
for Result:=0 to FStyleList.Count-1 do begin
if TStyleData(FStyleList[Result]).Name = AStyleName then
for Result:=0 to FCellStyleList.Count-1 do begin
if TCellStyleData(FCellStyleList[Result]).Name = AStyleName then
exit;
end;
Result := -1;
end;
function TsSpreadOpenDocReader.FindColumnByCol(AColIndex: Integer): Integer;
begin
for Result := 0 to FColumnList.Count-1 do
if TColumnData(FColumnList[Result]).Col = AColIndex then
exit;
Result := -1;
end;
function TsSpreadOpenDocReader.FindColStyleByName(AStyleName: String): Integer;
begin
for Result := 0 to FColumnStyleList.Count-1 do
if TColumnStyleData(FColumnStyleList[Result]).Name = AStyleName then
exit;
Result := -1;
end;
function TsSpreadOpenDocReader.GetAttrValue(ANode : TDOMNode; AAttrName : string) : string;
var
i : integer;
@ -383,11 +447,16 @@ var
FilePath : string;
UnZip : TUnZipper;
FileList : TStringList;
BodyNode, SpreadSheetNode, TableNode, RowNode, CellNode : TDOMNode;
BodyNode, SpreadSheetNode, TableNode, ColNode, RowNode, CellNode : TDOMNode;
StylesNode: TDOMNode;
ParamRowsRepeated, ParamColsRepeated, ParamValueType, ParamFormula : string;
TableStyleName: String;
RowsCount, ColsCount : integer;
colData: TColumnData;
colStyleIndex: Integer;
colStyleData: TColumnStyleData;
i: Integer;
s: String;
begin
//unzip content.xml into AFileName path
FilePath := GetTempDir(false);
@ -433,9 +502,36 @@ begin
TableNode := SpreadSheetNode.FindNode('table:table');
while Assigned(TableNode) do begin
FWorkSheet := aData.AddWorksheet(GetAttrValue(TableNode,'table:name'));
Row := 0;
//process each row inside the sheet
// Collect column styles used
Col := 0;
ColNode := TableNode.FindNode('table:table-column');
while Assigned(ColNode) do begin
if ColNode.NodeName = 'table:table-column' then begin;
s := GetAttrValue(ColNode, 'table:style-name');
colStyleIndex := FindColStyleByName(s);
if colStyleIndex <> -1 then begin
colStyleData := TColumnStyleData(FColumnStyleList[colStyleIndex]);
s := GetAttrValue(ColNode, 'table:default-cell-style-name');
if s <> '' then begin
colData := TColumnData.Create;
colData.Col := Col;
colData.ColStyleIndex := colStyleIndex;
colData.DefaultCellStyleIndex := FindCellStyleByName(s);
FColumnList.Add(colData);
end;
end;
s := GetAttrValue(ColNode, 'table:number-columns-repeated');
if s = '' then
inc(Col)
else
inc(col, StrToInt(s));
end;
ColNode := ColNode.NextSibling;
end;
// Process each row inside the sheet
Row := 0;
RowNode := TableNode.FindNode('table:table-row');
while Assigned(RowNode) do begin
@ -760,9 +856,11 @@ end;
procedure TsSpreadOpenDocReader.ReadStyles(AStylesNode: TDOMNode);
var
fs: TFormatSettings;
style: TStyleData;
style: TCellStyleData;
styleNode: TDOMNode;
styleChildNode: TDOMNode;
colStyle: TColumnStyleData;
colWidth: Double;
family: String;
styleName: String;
styleIndex: Integer;
@ -771,6 +869,8 @@ var
numFmtIndexDefault: Integer;
wrap: Boolean;
txtRot: TsTextRotation;
vertAlign: TsVertAlignment;
horAlign: TsHorAlignment;
borders: TsCellBorders;
borderStyles: TsCellBorderStyles;
bkClr: TsColorValue;
@ -857,6 +957,30 @@ begin
while Assigned(styleNode) do begin
if styleNode.NodeName = 'style:style' then begin
family := GetAttrValue(styleNode, 'style:family');
// Column styles
if family = 'table-column' then begin
styleName := GetAttrValue(styleNode, 'style:name');
styleChildNode := styleNode.FirstChild;
colWidth := -1;
while Assigned(styleChildNode) do begin
if styleChildNode.NodeName = 'style:table-column-properties' then begin
s := GetAttrValue(styleChildNode, 'style:column-width');
if s <> '' then begin
s := Copy(s, 1, Length(s)-2); // TO DO: use correct units!
colWidth := StrToFloat(s, fs);
break;
end;
end;
styleChildNode := styleChildNode.NextSibling;
end;
colStyle := TColumnStyleData.Create;
colStyle.Name := styleName;
colStyle.ColWidth := colWidth;
FColumnStyleList.Add(colStyle);
end;
// Cell styles
if family = 'table-cell' then begin
styleName := GetAttrValue(styleNode, 'style:name');
numFmtName := GetAttrValue(styleNode, 'style:data-style-name');
@ -868,6 +992,8 @@ begin
wrap := false;
bkClr := TsColorValue(-1);
txtRot := trHorizontal;
horAlign := haDefault;
vertAlign := vaDefault;
styleChildNode := styleNode.FirstChild;
while Assigned(styleChildNode) do begin
@ -920,19 +1046,35 @@ begin
if s = 'ttb' then
txtRot := rtStacked;
// Vertical text alignment
s := GetAttrValue(styleChildNode, 'style:vertical-align');
if s = 'top' then
vertAlign := vaTop
else if s = 'middle' then
vertAlign := vaCenter
else if s = 'bottom' then
vertAlign := vaBottom;
end else
if styleChildNode.NodeName = 'style:paragraph-properties' then begin
//
// Horizontal text alignment
s := GetAttrValue(styleChildNode, 'fo:text-align');
if s = 'start' then
horAlign := haLeft
else if s = 'end' then
horAlign := haRight
else if s = 'center' then
horAlign := haCenter;
end;
styleChildNode := styleChildNode.NextSibling;
end;
style := TStyleData.Create;
style := TCellStyleData.Create;
style.Name := stylename;
style.FontIndex := 0;
style.NumFormatIndex := numFmtIndex;
style.HorAlignment := haDefault;
style.VertAlignment := vaDefault;
style.HorAlignment := horAlign;
style.VertAlignment := vertAlign;
style.WordWrap := wrap;
style.TextRotation := txtRot;
style.Borders := borders;
@ -940,7 +1082,7 @@ begin
style.BackgroundColor := IfThen(bkClr = TsColorValue(-1), scNotDefined,
Workbook.AddColorToPalette(bkClr));
styleIndex := FStyleList.Add(style);
styleIndex := FCellStyleList.Add(style);
end;
end;
styleNode := styleNode.NextSibling;

View File

@ -924,9 +924,11 @@ begin
horAlign := haRight
else
horAlign := haLeft;
{
if txtRot = rt90DegreeCounterClockwiseRotation then begin
if horAlign = haRight then horAlign := haLeft else horAlign := haRight;
end;
}
end;
InflateRect(ARect, -constCellPadding, -constCellPadding);