fpspreadsheet: Attempt to implement basic OOXML support

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1861 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-08-29 10:55:22 +00:00
parent 63b8256e75
commit 4dafa5ce8d
4 changed files with 133 additions and 273 deletions

View File

@ -1,21 +1,23 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<CONFIG> <CONFIG>
<ProjectOptions> <ProjectOptions>
<Version Value="9"/>
<PathDelim Value="\"/> <PathDelim Value="\"/>
<Version Value="7"/>
<General> <General>
<Flags> <Flags>
<LRSInOutputDirectory Value="False"/> <LRSInOutputDirectory Value="False"/>
</Flags> </Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/> <MainUnit Value="0"/>
<TargetFileExt Value=".exe"/>
<Title Value="ooxmlwrite"/> <Title Value="ooxmlwrite"/>
<UseAppBundle Value="False"/> <UseAppBundle Value="False"/>
<ActiveEditorIndexAtStart Value="1"/>
</General> </General>
<VersionInfo> <VersionInfo>
<ProjectVersion Value=""/> <StringTable ProductVersion=""/>
</VersionInfo> </VersionInfo>
<BuildModes Count="1">
<Item1 Name="default" Default="True"/>
</BuildModes>
<PublishOptions> <PublishOptions>
<Version Value="2"/> <Version Value="2"/>
<IgnoreBinaries Value="False"/> <IgnoreBinaries Value="False"/>
@ -33,251 +35,30 @@
<PackageName Value="laz_fpspreadsheet"/> <PackageName Value="laz_fpspreadsheet"/>
</Item1> </Item1>
</RequiredPackages> </RequiredPackages>
<Units Count="14"> <Units Count="1">
<Unit0> <Unit0>
<Filename Value="ooxmlwrite.lpr"/> <Filename Value="ooxmlwrite.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<UnitName Value="ooxmlwrite"/> <UnitName Value="ooxmlwrite"/>
<CursorPos X="81" Y="57"/>
<TopLine Value="46"/>
<EditorIndex Value="0"/>
<UsageCount Value="309"/>
<Loaded Value="True"/>
</Unit0> </Unit0>
<Unit1>
<Filename Value="..\fpolestorage.pas"/>
<UnitName Value="fpolestorage"/>
<CursorPos X="1" Y="1"/>
<TopLine Value="1"/>
<UsageCount Value="18"/>
</Unit1>
<Unit2>
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
<UnitName Value="Win32WSStdCtrls"/>
<CursorPos X="35" Y="720"/>
<TopLine Value="713"/>
<UsageCount Value="75"/>
</Unit2>
<Unit3>
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
<UnitName Value="ComponentEditors"/>
<CursorPos X="40" Y="332"/>
<TopLine Value="330"/>
<UsageCount Value="73"/>
</Unit3>
<Unit4>
<Filename Value="..\..\xlsbiff5.pas"/>
<UnitName Value="xlsbiff5"/>
<CursorPos X="26" Y="95"/>
<TopLine Value="92"/>
<EditorIndex Value="5"/>
<UsageCount Value="140"/>
<Loaded Value="True"/>
</Unit4>
<Unit5>
<Filename Value="..\..\fpsutils.pas"/>
<UnitName Value="fpsutils"/>
<CursorPos X="1" Y="49"/>
<TopLine Value="30"/>
<EditorIndex Value="4"/>
<UsageCount Value="140"/>
<Loaded Value="True"/>
</Unit5>
<Unit6>
<Filename Value="..\..\xlsbiff2.pas"/>
<UnitName Value="xlsbiff2"/>
<CursorPos X="1" Y="360"/>
<TopLine Value="339"/>
<EditorIndex Value="6"/>
<UsageCount Value="139"/>
<Loaded Value="True"/>
</Unit6>
<Unit7>
<Filename Value="..\..\fpolestorage.pas"/>
<UnitName Value="fpolestorage"/>
<CursorPos X="30" Y="654"/>
<TopLine Value="642"/>
<EditorIndex Value="7"/>
<UsageCount Value="139"/>
<Loaded Value="True"/>
</Unit7>
<Unit8>
<Filename Value="..\..\..\..\..\lazarus26\fpc\2.2.2\source\rtl\objpas\classes\classesh.inc"/>
<CursorPos X="19" Y="562"/>
<TopLine Value="553"/>
<UsageCount Value="40"/>
</Unit8>
<Unit9>
<Filename Value="..\..\..\..\..\lazarus26\fpc\2.2.2\source\rtl\objpas\classes\streams.inc"/>
<CursorPos X="21" Y="158"/>
<TopLine Value="151"/>
<UsageCount Value="40"/>
</Unit9>
<Unit10>
<Filename Value="..\..\fpspreadsheet.pas"/>
<UnitName Value="fpspreadsheet"/>
<CursorPos X="28" Y="26"/>
<TopLine Value="12"/>
<EditorIndex Value="3"/>
<UsageCount Value="95"/>
<Loaded Value="True"/>
</Unit10>
<Unit11>
<Filename Value="..\..\..\..\..\lazarus\lcl\include\customtrayicon.inc"/>
<CursorPos X="22" Y="203"/>
<TopLine Value="197"/>
<UsageCount Value="66"/>
</Unit11>
<Unit12>
<Filename Value="..\..\fpsopendocument.pas"/>
<UnitName Value="fpsopendocument"/>
<CursorPos X="3" Y="296"/>
<TopLine Value="285"/>
<EditorIndex Value="1"/>
<UsageCount Value="13"/>
<Loaded Value="True"/>
</Unit12>
<Unit13>
<Filename Value="..\..\xlsxooxml.pas"/>
<UnitName Value="xlsxooxml"/>
<CursorPos X="1" Y="248"/>
<TopLine Value="244"/>
<EditorIndex Value="2"/>
<UsageCount Value="13"/>
<Loaded Value="True"/>
</Unit13>
</Units> </Units>
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="567" Column="5" TopLine="548"/>
</Position1>
<Position2>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="622" Column="1" TopLine="618"/>
</Position2>
<Position3>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="621" Column="29" TopLine="611"/>
</Position3>
<Position4>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="428" Column="5" TopLine="403"/>
</Position4>
<Position5>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="458" Column="15" TopLine="434"/>
</Position5>
<Position6>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="386" Column="1" TopLine="372"/>
</Position6>
<Position7>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="390" Column="26" TopLine="377"/>
</Position7>
<Position8>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="420" Column="32" TopLine="407"/>
</Position8>
<Position9>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="421" Column="14" TopLine="408"/>
</Position9>
<Position10>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="460" Column="33" TopLine="440"/>
</Position10>
<Position11>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="181" Column="91" TopLine="160"/>
</Position11>
<Position12>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="769" Column="83" TopLine="754"/>
</Position12>
<Position13>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="102" Column="15" TopLine="89"/>
</Position13>
<Position14>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="103" Column="15" TopLine="90"/>
</Position14>
<Position15>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="404" Column="5" TopLine="379"/>
</Position15>
<Position16>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="187" Column="1" TopLine="172"/>
</Position16>
<Position17>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="380" Column="17" TopLine="362"/>
</Position17>
<Position18>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="412" Column="1" TopLine="404"/>
</Position18>
<Position19>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="716" Column="1" TopLine="702"/>
</Position19>
<Position20>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="167" Column="17" TopLine="154"/>
</Position20>
<Position21>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="69" Column="1" TopLine="57"/>
</Position21>
<Position22>
<Filename Value="ooxmlwrite.lpr"/>
<Caret Line="68" Column="57" TopLine="46"/>
</Position22>
<Position23>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="102" Column="1" TopLine="77"/>
</Position23>
<Position24>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="89" Column="1" TopLine="79"/>
</Position24>
<Position25>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="50" Column="30" TopLine="37"/>
</Position25>
<Position26>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="51" Column="58" TopLine="35"/>
</Position26>
<Position27>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="80" Column="70" TopLine="67"/>
</Position27>
<Position28>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="194" Column="17" TopLine="181"/>
</Position28>
<Position29>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="324" Column="46" TopLine="306"/>
</Position29>
<Position30>
<Filename Value="..\..\xlsxooxml.pas"/>
<Caret Line="211" Column="20" TopLine="188"/>
</Position30>
</JumpHistory>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>
<Version Value="8"/> <Version Value="10"/>
<PathDelim Value="\"/> <PathDelim Value="\"/>
<SearchPaths> <SearchPaths>
<OtherUnitFiles Value="..\"/> <OtherUnitFiles Value=".."/>
<SrcPath Value="..\"/> <SrcPath Value=".."/>
</SearchPaths> </SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<Other> <Other>
<CompilerMessages>
<UseMsgFile Value="True"/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/> <CompilerPath Value="$(CompPath)"/>
</Other> </Other>
</CompilerOptions> </CompilerOptions>

View File

@ -15,7 +15,6 @@ uses
var var
MyWorkbook: TsWorkbook; MyWorkbook: TsWorkbook;
MyWorksheet: TsWorksheet; MyWorksheet: TsWorksheet;
MyFormula: TRPNFormula;
MyDir: string; MyDir: string;
i: Integer; i: Integer;
a: TStringList; a: TStringList;

View File

@ -190,6 +190,8 @@ type
{ Base methods } { Base methods }
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
{ Utils }
class function CellPosToText(ARow, ACol: Cardinal): string;
{ Data manipulation methods } { Data manipulation methods }
function FindCell(ARow, ACol: Cardinal): PCell; function FindCell(ARow, ACol: Cardinal): PCell;
function GetCell(ARow, ACol: Cardinal): PCell; function GetCell(ARow, ACol: Cardinal): PCell;
@ -388,6 +390,19 @@ begin
inherited Destroy; inherited Destroy;
end; end;
{@@ Converts a FPSpreadsheet cell position, which is Row, Col in numbers
and zero based, to a textual representation which is [Col][Row],
being that the Col is in letters and the row is in 1-based numbers }
class function TsWorksheet.CellPosToText(ARow, ACol: Cardinal): string;
var
lStr: string;
begin
lStr := '';
if ACol < 26 then lStr := Char(ACol+54);
Result := Format('%s%d', [lStr, ARow+1]);
end;
{@@ {@@
Tryes to locate a Cell in the list of already Tryes to locate a Cell in the list of already
written Cells written Cells

View File

@ -32,6 +32,7 @@ interface
uses uses
Classes, SysUtils, Classes, SysUtils,
fpszipper, {NOTE: fpszipper is the latest zipper.pp Change to standard zipper when FPC 2.4 is released } fpszipper, {NOTE: fpszipper is the latest zipper.pp Change to standard zipper when FPC 2.4 is released }
{xmlread, DOM,} AVL_Tree,
fpspreadsheet; fpspreadsheet;
type type
@ -51,6 +52,7 @@ type
FSRelsRels: TStringStream; FSRelsRels: TStringStream;
FSWorkbook, FSWorkbookRels, FSStyles, FSSharedStrings: TStringStream; FSWorkbook, FSWorkbookRels, FSStyles, FSSharedStrings: TStringStream;
FSSheets: array of TStringStream; FSSheets: array of TStringStream;
FCurSheetNum: Integer;
{ Routines to write those files } { Routines to write those files }
procedure WriteGlobalFiles; procedure WriteGlobalFiles;
procedure WriteContent(AData: TsWorkbook); procedure WriteContent(AData: TsWorkbook);
@ -244,48 +246,99 @@ begin
'</sst>'; '</sst>';
end; end;
{
FSheets[CurStr] :=
XML_HEADER + LineEnding +
'<worksheet xmlns="' + SCHEMAS_SPREADML + '" xmlns:r="' + SCHEMAS_DOC_RELS + '">' + LineEnding +
' <sheetViews>' + LineEnding +
' <sheetView workbookViewId="0" />' + LineEnding +
' </sheetViews>' + LineEnding +
' <sheetData>' + LineEnding +
' <row r="1" spans="1:4">' + LineEnding +
' <c r="A1">' + LineEnding +
' <v>1</v>' + LineEnding +
' </c>' + LineEnding +
' <c r="B1">' + LineEnding +
' <v>2</v>' + LineEnding +
' </c>' + LineEnding +
' <c r="C1">' + LineEnding +
' <v>3</v>' + LineEnding +
' </c>' + LineEnding +
' <c r="D1">' + LineEnding +
' <v>4</v>' + LineEnding +
' </c>' + LineEnding +
' </row>' + LineEnding +
' <row r="2" spans="1:4">' + LineEnding +
' <c r="A2" t="s">' + LineEnding +
' <v>0</v>' + LineEnding +
' </c>' + LineEnding +
' <c r="B2" t="s">' + LineEnding +
' <v>1</v>' + LineEnding +
' </c>' + LineEnding +
' <c r="C2" t="s">' + LineEnding +
' <v>2</v>' + LineEnding +
' </c>' + LineEnding +
' <c r="D2" t="s">' + LineEnding +
' <v>3</v>' + LineEnding +
' </c>' + LineEnding +
' </row>' + LineEnding +
' </sheetData>' + LineEnding +
'</worksheet>';
}
procedure TsSpreadOOXMLWriter.WriteWorksheet(CurSheet: TsWorksheet); procedure TsSpreadOOXMLWriter.WriteWorksheet(CurSheet: TsWorksheet);
var var
CurStr: Integer; j, k: Integer;
CurCell: PCell;
CurRow: array of PCell;
LastColNum: Cardinal;
LCell: TCell;
AVLNode: TAVLTreeNode;
CellPosText: string;
begin begin
CurStr := Length(FSheets); FCurSheetNum := Length(FSheets);
SetLength(FSheets, CurStr + 1); SetLength(FSheets, FCurSheetNum + 1);
FSheets[CurStr] := LastColNum := CurSheet.GetLastColNumber;
// Header
FSheets[FCurSheetNum] :=
XML_HEADER + LineEnding + XML_HEADER + LineEnding +
'<worksheet xmlns="' + SCHEMAS_SPREADML + '" xmlns:r="' + SCHEMAS_DOC_RELS + '">' + LineEnding + '<worksheet xmlns="' + SCHEMAS_SPREADML + '" xmlns:r="' + SCHEMAS_DOC_RELS + '">' + LineEnding +
' <sheetViews>' + LineEnding + ' <sheetViews>' + LineEnding +
' <sheetView workbookViewId="0" />' + LineEnding + ' <sheetView workbookViewId="0" />' + LineEnding +
' </sheetViews>' + LineEnding + ' </sheetViews>' + LineEnding +
' <sheetData>' + LineEnding + ' <sheetData>' + LineEnding;
' <row r="1" spans="1:4">' + LineEnding +
' <c r="A1">' + LineEnding + // The cells need to be written in order, row by row, cell by cell
' <v>1</v>' + LineEnding + for j := 0 to CurSheet.GetLastRowNumber do
' </c>' + LineEnding + begin
' <c r="B1">' + LineEnding + FSheets[FCurSheetNum] := FSheets[FCurSheetNum] +
' <v>2</v>' + LineEnding + Format(' <row r="%d" spans="1:%d">', [j+1,LastColNum+1]) + LineEnding;
' </c>' + LineEnding +
' <c r="C1">' + LineEnding + // Write cells from this row.
' <v>3</v>' + LineEnding + for k := 0 to LastColNum do
' </c>' + LineEnding + begin
' <c r="D1">' + LineEnding + LCell.Row := j;
' <v>4</v>' + LineEnding + LCell.Col := k;
' </c>' + LineEnding + AVLNode := CurSheet.Cells.Find(@LCell);
' </row>' + LineEnding + if Assigned(AVLNode) then
' <row r="2" spans="1:4">' + LineEnding + WriteCellCallback(PCell(AVLNode.Data), nil)
' <c r="A2" t="s">' + LineEnding + else
' <v>0</v>' + LineEnding + begin
' </c>' + LineEnding + CellPosText := CurSheet.CellPosToText(j, k);
' <c r="B2" t="s">' + LineEnding + FSheets[FCurSheetNum] := FSheets[FCurSheetNum] +
' <v>1</v>' + LineEnding + Format(' <c r="%s">', [CellPosText]) + LineEnding +
' </c>' + LineEnding + ' <v></v>' + LineEnding +
' <c r="C2" t="s">' + LineEnding + ' </c>' + LineEnding;
' <v>2</v>' + LineEnding + end;
' </c>' + LineEnding + end;
' <c r="D2" t="s">' + LineEnding +
' <v>3</v>' + LineEnding + FSheets[FCurSheetNum] := FSheets[FCurSheetNum] +
' </c>' + LineEnding + ' </row>' + LineEnding;
' </row>' + LineEnding + end;
// Footer
FSheets[FCurSheetNum] := FSheets[FCurSheetNum] +
' </sheetData>' + LineEnding + ' </sheetData>' + LineEnding +
'</worksheet>'; '</worksheet>';
end; end;
@ -383,8 +436,14 @@ end;
} }
procedure TsSpreadOOXMLWriter.WriteLabel(AStream: TStream; const ARow, procedure TsSpreadOOXMLWriter.WriteLabel(AStream: TStream; const ARow,
ACol: Word; const AValue: string; ACell: PCell); ACol: Word; const AValue: string; ACell: PCell);
var
CellPosText: string;
begin begin
CellPosText := TsWorksheet.CellPosToText(ARow, ACol);
FSheets[FCurSheetNum] := FSheets[FCurSheetNum] +
Format(' <c r="%s" t="s">', [CellPosText]) + LineEnding +
' <v>2</v>' + LineEnding +
' </c>' + LineEnding;
end; end;
{ {
@ -392,8 +451,14 @@ end;
} }
procedure TsSpreadOOXMLWriter.WriteNumber(AStream: TStream; const ARow, procedure TsSpreadOOXMLWriter.WriteNumber(AStream: TStream; const ARow,
ACol: Cardinal; const AValue: double; ACell: PCell); ACol: Cardinal; const AValue: double; ACell: PCell);
var
CellPosText: String;
begin begin
CellPosText := TsWorksheet.CellPosToText(ARow, ACol);
FSheets[FCurSheetNum] := FSheets[FCurSheetNum] +
Format(' <c r="%s">', [CellPosText]) + LineEnding +
' <v>1</v>' + LineEnding +
' </c>' + LineEnding;
end; end;
{ {