lazarus-ccr/components/fpspreadsheet/wikitable.pas
2013-06-12 11:02:02 +00:00

421 lines
9.9 KiB
ObjectPascal

(*
wikitable.pas
One unit which handles multiple wiki table formats
Format simplepipes:
|| || title1 || title2 || title3
| [link_to_something|http://google.com]| {color:red}FAILED{color}| {color:red}FAILED{color}| {color:green}PASS{color}
Format mediawiki:
{| border="1" cellpadding="2" class="wikitable sortable"
|-
|
! Title
|-
| [http://google.com link_to_something]
! style="background-color:green;color:white;" | PASS
|}
AUTHORS: Felipe Monteiro de Carvalho
*)
unit wikitable;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
fpimage, fgl,
fpspreadsheet, xlscommon, fpsutils, lconvencoding;
type
TWikiTableToken = class
public
BackgroundColor: TsColor;
UseBackgroundColor: Boolean;
Bold: Boolean;
Value: string;
end;
TWikiTableTokenList = specialize TFPGList<TWikiTableToken>;
{ TWikiTableTokenizer }
TWikiTableTokenizer = class
public
Tokens: TWikiTableTokenList;
constructor Create; virtual;
destructor Destroy; override;
procedure Clear;
function AddToken(AValue: string): TWikiTableToken;
procedure TokenizeString_Pipes(AStr: string);
end;
{ TsWikiTableReader }
TsWikiTableReader = class(TsCustomSpreadReader)
private
FWorksheet: TsWorksheet;
public
SubFormat: TsSpreadsheetFormat;
{ General reading methods }
procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); override;
procedure ReadFromStrings_Pipes(AStrings: TStrings; AData: TsWorkbook);
end;
{ TsWikiTable_PipesReader }
TsWikiTable_PipesReader = class(TsWikiTableReader)
public
constructor Create; override;
end;
{ TsWikiTableWriter }
TsWikiTableWriter = class(TsCustomSpreadWriter)
private
FWorksheet: TsWorksheet;
public
SubFormat: TsSpreadsheetFormat;
{ General writing methods }
procedure WriteToStrings(AStrings: TStrings; AData: TsWorkbook); override;
procedure WriteToStrings_WikiMedia(AStrings: TStrings; AData: TsWorkbook);
end;
{ TsWikiTable_WikiMediaWriter }
TsWikiTable_WikiMediaWriter = class(TsWikiTableWriter)
public
constructor Create; override;
end;
implementation
{ TWikiTableTokenizer }
constructor TWikiTableTokenizer.Create;
begin
inherited Create;
Tokens := TWikiTableTokenList.Create;
end;
destructor TWikiTableTokenizer.Destroy;
begin
Clear;
Tokens.Free;
inherited Destroy;
end;
procedure TWikiTableTokenizer.Clear;
var
i: Integer;
begin
for i := 0 to Tokens.Count-1 do
Tokens.Items[i].Free;
Tokens.Clear;
end;
function TWikiTableTokenizer.AddToken(AValue: string): TWikiTableToken;
begin
Result := TWikiTableToken.Create;
Result.Value := AValue;
Tokens.Add(Result);
end;
(*
Format simplepipes:
|| || title1 || title2 || title3
| [link_to_something|http://google.com]| {color:red}FAILED{color}| {color:red}FAILED{color}| {color:green}PASS{color}
*)
procedure TWikiTableTokenizer.TokenizeString_Pipes(AStr: string);
const
Str_Pipe: Char = '|';
Str_LinkStart: Char = '[';
Str_LinkEnd: Char = ']';
Str_FormatStart: Char = '{';
Str_FormatEnd: Char = '}';
Str_EmptySpaces: set of Char = [' '];
var
i: Integer;
lTmpStr: string = '';
lFormatStr: string = '';
lState: Integer;
lLookAheadChar, lCurChar: Char;
lIsTitle: Boolean = False;
lCurBackgroundColor: TsColor;
lUseBackgroundColor: Boolean = False;
lCurToken: TWikiTableToken;
procedure DoAddToken();
begin
lCurToken := AddToken(lTmpStr);
lCurToken.Bold := lIsTitle;
lCurToken.UseBackgroundColor := lUseBackgroundColor;
if lUseBackgroundColor then
lCurToken.BackgroundColor := lCurBackgroundColor;
end;
begin
Clear;
lState := 0;
i := 1;
while i <= Length(AStr) do
begin
lCurChar := AStr[i];
if i < Length(AStr) then lLookAheadChar := AStr[i+1];
case lState of
0: // Line-start or otherwise reading a pipe separator, expecting a | or ||
begin
if lCurChar = Str_Pipe then
begin
lState := 1;
lIsTitle := False;
if lLookAheadChar = Str_Pipe then
begin
Inc(i);
lIsTitle := True;
end;
Inc(i);
lUseBackgroundColor := False;
lTmpStr := '';
end
else if lCurChar in Str_EmptySpaces then
begin
// Do nothing
Inc(i);
end
else
begin
// Error!!!
raise Exception.Create('[TWikiTableTokenizer.TokenizeString] Wrong char!');
end;
end;
1: // Reading cell text
begin
if lCurChar = Str_Pipe then
begin
lState := 0;
DoAddToken();
end
else if lCurChar = Str_LinkStart then
begin
lState := 2;
Inc(i);
end
else if lCurChar = Str_FormatStart then
begin
lState := 4;
Inc(i);
end
else
begin
lTmpStr := lTmpStr + lCurChar;
Inc(i);
end;
end;
2: // Link text reading
begin
if lCurChar = Str_Pipe then
begin
lState := 3;
Inc(i);
end
else
begin
lTmpStr := lTmpStr + lCurChar;
Inc(i);
end;
end;
3: // Link target reading
begin
if lCurChar = Str_LinkEnd then
begin
lState := 1;
Inc(i);
end
else
begin
Inc(i);
end;
end;
4: // Color start reading
begin
if lCurChar = Str_FormatEnd then
begin
lState := 1;
Inc(i);
lFormatStr := LowerCase(Trim(lFormatStr));
if lFormatStr = 'color:red' then lCurBackgroundColor := scRED
else if lFormatStr = 'color:green' then lCurBackgroundColor := scGREEN
else if lFormatStr = 'color:yellow' then lCurBackgroundColor := scYELLOW
//
else if lFormatStr = 'color:orange' then lCurBackgroundColor := scOrange
else lCurBackgroundColor := scWHITE;
lUseBackgroundColor := True;
lFormatStr := '';
end
else
begin
lFormatStr := lFormatStr + lCurChar;
Inc(i);
end;
end;
end;
end;
// rest after the last || is also a token
if lTmpStr <> '' then DoAddToken();
// If there is a token still to be added, add it now
if (lState = 0) and (lTmpStr <> '') then AddToken(lTmpStr);
end;
{ TsWikiTableReader }
procedure TsWikiTableReader.ReadFromStrings(AStrings: TStrings;
AData: TsWorkbook);
begin
case SubFormat of
sfWikiTable_Pipes: ReadFromStrings_Pipes(AStrings, AData);
end;
end;
procedure TsWikiTableReader.ReadFromStrings_Pipes(AStrings: TStrings;
AData: TsWorkbook);
var
i, j: Integer;
lCurLine: String;
lLineSplitter: TWikiTableTokenizer;
lCurToken: TWikiTableToken;
begin
FWorksheet := AData.AddWorksheet('Table');
lLineSplitter := TWikiTableTokenizer.Create;
try
for i := 0 to AStrings.Count-1 do
begin
lCurLine := AStrings[i];
lLineSplitter.TokenizeString_Pipes(lCurLine);
for j := 0 to lLineSplitter.Tokens.Count-1 do
begin
lCurToken := lLineSplitter.Tokens[j];
FWorksheet.WriteUTF8Text(i, j, lCurToken.Value);
if lCurToken.Bold then FWorksheet.WriteUsedFormatting(i, j, [uffBold]);
if lCurToken.UseBackgroundColor then FWorksheet.WriteBackgroundColor(i, j, lCurToken.BackgroundColor);
end;
end;
finally
lLineSplitter.Free;
end;
end;
{ TsWikiTable_PipesReader }
constructor TsWikiTable_PipesReader.Create;
begin
inherited Create;
SubFormat := sfWikiTable_Pipes;
end;
{ TsWikiTableWriter }
procedure TsWikiTableWriter.WriteToStrings(AStrings: TStrings; AData: TsWorkbook);
begin
case SubFormat of
sfWikiTable_WikiMedia: WriteToStrings_WikiMedia(AStrings, AData);
end;
end;
(*
Format mediawiki:
{| border="1" cellpadding="2" class="wikitable sortable"
|-
|
! Title
|-
| [http://google.com link_to_something]
! style="background-color:green;color:white;" | PASS
|}
*)
procedure TsWikiTableWriter.WriteToStrings_WikiMedia(AStrings: TStrings;
AData: TsWorkbook);
var
i, j: Integer;
lCurStr: string = '';
lCurCell: PCell;
lCurUsedFormatting: TsUsedFormattingFields;
lCurColor: TsColor;
lColorStr: String;
begin
AStrings.Add('{| border="1" cellpadding="2" class="wikitable sortable"');
FWorksheet := AData.GetFirstWorksheet();
for i := 0 to FWorksheet.GetLastRowNumber() do
begin
AStrings.Add('|-');
for j := 0 to FWorksheet.GetLastColNumber() do
begin
lCurStr := FWorksheet.ReadAsUTF8Text(i, j);
lCurUsedFormatting := FWorksheet.ReadUsedFormatting(i, j);
if uffBackgroundColor in lCurUsedFormatting then
begin
lCurColor := FWorksheet.ReadBackgroundColor(i, j);
case lCurColor of
scBlack: lColorStr := 'style="background-color:black;color:white;"';
scWhite: lColorStr := 'style="background-color:white;color:black;"';
scRed: lColorStr := 'style="background-color:red;color:white;"';
scGREEN: lColorStr := 'style="background-color:green;color:white;"';
scBLUE: lColorStr := 'style="background-color:blue;color:white;"';
scYELLOW: lColorStr := 'style="background-color:yellow;color:black;"';
{scMAGENTA, // FF00FFH
scCYAN, // 00FFFFH
scDarkRed, // 800000H
scDarkGreen,// 008000H
scDarkBlue, // 000080H
scOLIVE, // 808000H
scPURPLE, // 800080H
scTEAL, // 008080H
scSilver, // C0C0C0H
scGrey, // 808080H
//
scGrey10pct,// E6E6E6H
scGrey20pct // CCCCCCH }
scOrange: lColorStr := 'style="background-color:orange;color:white;"';
end;
lCurStr := lColorStr + ' |' + lCurStr;
end;
if uffBold in lCurUsedFormatting then lCurStr := '!' + lCurStr
else lCurStr := '|' + lCurStr;
AStrings.Add(lCurStr);
end;
end;
AStrings.Add('|}');
end;
{ TsWikiTable_WikiMediaWriter }
constructor TsWikiTable_WikiMediaWriter.Create;
begin
inherited Create;
SubFormat := sfWikiTable_WikiMedia;
end;
initialization
RegisterSpreadFormat(TsWikiTable_PipesReader, nil, sfWikiTable_Pipes);
RegisterSpreadFormat(nil, TsWikiTable_WikiMediaWriter, sfWikiTable_WikiMedia);
end.