From 313daa2eafb6face2ae05eb7aa0be78d322b54b7 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Sun, 20 Apr 2014 16:07:53 +0000 Subject: [PATCH] fpspreadsheet: Complete prepared read/write support for cell wordwrap in biff8 and fpspreadsheetgrid git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2954 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/excel8demo/excel8write.lpr | 5 +- .../examples/fpsgrid/fpsgrid.lpi | 296 ++++++++++++------ .../fpspreadsheet/fpspreadsheetgrid.pas | 5 + .../fpspreadsheet/tests/formattests.pas | 54 ++++ components/fpspreadsheet/xlsbiff8.pas | 33 +- 5 files changed, 289 insertions(+), 104 deletions(-) diff --git a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr index a651b2de6..2f30a19f3 100644 --- a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr +++ b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr @@ -52,6 +52,10 @@ begin lCell^.BackgroundColor := scPURPLE; lCell^.UsedFormattingFields := [uffBackgroundColor]; + // Word-wrapped long text + MyWorksheet.WriteUTF8Text(6, 3, 'This is a very, very, very, very long text.'); + MyWorksheet.WriteUsedFormatting(6, 3, [uffWordwrap]); + { Uncomment this to test large XLS files for i := 2 to 20 do begin @@ -61,7 +65,6 @@ begin MyWorksheet.WriteAnsiText(i, 3, ParamStr(0)); end; } - // Write the formula E1 = A1 + B1 SetLength(MyRPNFormula, 3); MyRPNFormula[0].ElementKind := fekCell; diff --git a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi index e40b049ad..a53fadb58 100644 --- a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi +++ b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi @@ -38,15 +38,17 @@ - + + - - + + + @@ -55,35 +57,35 @@ - + - - - + + + - + - - - - - - + + + - + - - - + + + + + + @@ -92,7 +94,7 @@ - + @@ -100,7 +102,7 @@ - + @@ -108,7 +110,7 @@ - + @@ -116,167 +118,266 @@ - + - + - - - + - + - - - + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -303,6 +404,11 @@ + + + + + diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index 5e6aa13a0..35cf90eb4 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -217,6 +217,11 @@ begin // Default alignment of number is right-justify if lCell^.ContentType = cctNumber then ts.Alignment := taRightJustify; + // Word wrap? + if (uffWordWrap in lCell^.UsedFormattingFields) then begin + ts.Wordbreak := true; + ts.SingleLine := false; + end; end; end; Canvas.TextStyle := ts; diff --git a/components/fpspreadsheet/tests/formattests.pas b/components/fpspreadsheet/tests/formattests.pas index ada997335..ad5564a50 100644 --- a/components/fpspreadsheet/tests/formattests.pas +++ b/components/fpspreadsheet/tests/formattests.pas @@ -49,6 +49,8 @@ type procedure TestWriteReadDateTimeFormats; // Test column width procedure TestWriteReadColWidths; + // Test word wrapping + procedure TestWriteReadWordWrap; end; implementation @@ -274,6 +276,58 @@ begin DeleteFile(TempFile); end; +procedure TSpreadWriteReadFormatTests.TestWriteReadWordWrap; +const + LONGTEXT = 'This is a very, very, very, very long text.'; +var + MyWorksheet: TsWorksheet; + MyWorkbook: TsWorkbook; + MyCell: PCell; + TempFile: string; //write xls/xml to this file and read back from it +begin + TempFile:=GetTempFileName; + {// Not needed: use workbook.writetofile with overwrite=true + if fileexists(TempFile) then + DeleteFile(TempFile); + } + // Write out all test values: + // Cell A1 is word-wrapped, Cell B1 is NOT word-wrapped + MyWorkbook := TsWorkbook.Create; + MyWorkSheet:= MyWorkBook.AddWorksheet(FmtNumbersSheet); + MyWorksheet.WriteUTF8Text(0, 0, LONGTEXT); + MyWorksheet.WriteUsedFormatting(0, 0, [uffWordwrap]); + MyCell := MyWorksheet.FindCell(0, 0); + if MyCell = nil then + fail('Error in test code. Failed to get word-wrapped cell.'); + CheckEquals((uffWordWrap in MyCell^.UsedFormattingFields), true, 'Test unsaved word wrap mismatch cell ' + CellNotation(MyWorksheet,0,0)); + MyWorksheet.WriteUTF8Text(1, 0, LONGTEXT); + MyWorksheet.WriteUsedFormatting(1, 0, []); + MyCell := MyWorksheet.FindCell(1, 0); + if MyCell = nil then + fail('Error in test code. Failed to get word-wrapped cell.'); + CheckEquals((uffWordWrap in MyCell^.UsedFormattingFields), false, 'Test unsaved non-wrapped cell mismatch, cell ' + CellNotation(MyWorksheet,0,0)); + MyWorkBook.WriteToFile(TempFile,sfExcel8,true); + MyWorkbook.Free; + + // Open the spreadsheet, as biff8 + MyWorkbook := TsWorkbook.Create; + MyWorkbook.ReadFromFile(TempFile, sfExcel8); + MyWorksheet:=GetWorksheetByName(MyWorkBook, FmtNumbersSheet); + if MyWorksheet=nil then + fail('Error in test code. Failed to get named worksheet'); + MyCell := MyWorksheet.FindCell(0, 0); + if MyCell = nil then + fail('Error in test code. Failed to get word-wrapped cell.'); + CheckEquals((uffWordWrap in MyCell^.UsedFormattingFields), true, 'failed to return correct word-wrap flag, cell ' + CellNotation(MyWorksheet,0,0)); + MyCell := MyWorksheet.FindCell(1, 0); + if MyCell = nil then + fail('Error in test code. Failed to get non-wrapped cell.'); + CheckEquals((uffWordWrap in MyCell^.UsedFormattingFields), false, 'failed to return correct word-wrap flag, cell ' + CellNotation(MyWorksheet,0,0)); + // Finalization + MyWorkbook.Free; + + DeleteFile(TempFile); +end; initialization RegisterTest(TSpreadWriteReadFormatTests); diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 463d0ea7a..6beae8cde 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -66,6 +66,7 @@ type TXFRecordData = class public FormatIndex: Integer; + WordWrap: Boolean; Borders: TsCellBorders; { FontIndex: Integer; @@ -156,6 +157,10 @@ type protected procedure AddDefaultFormats(); override; procedure WriteColInfo(AStream: TStream; ASheet: TsWorksheet; ACol: PCol); + procedure WriteXF(AStream: TStream; AFontIndex: Word; + AFormatIndex: Word; AXF_TYPE_PROT, ATextRotation: Byte; ABorders: TsCellBorders; + AddWordWrap: Boolean = false; AddBackground: Boolean = false; + ABackgroundColor: TsColor = scSilver); public // constructor Create; // destructor Destroy; override; @@ -181,9 +186,6 @@ type procedure WriteStyle(AStream: TStream); procedure WriteWindow1(AStream: TStream); procedure WriteWindow2(AStream: TStream; ASheetSelected: Boolean); - procedure WriteXF(AStream: TStream; AFontIndex: Word; - AFormatIndex: Word; AXF_TYPE_PROT, ATextRotation: Byte; ABorders: TsCellBorders; - AddBackground: Boolean = False; ABackgroundColor: TsColor = scSilver); end; implementation @@ -302,7 +304,9 @@ const MASK_XF_TYPE_PROT = $0007; MASK_XF_TYPE_PROT_PARENT = $FFF0; + MASK_XF_HOR_ALIGN = $07; MASK_XF_VERT_ALIGN = $70; + MASK_XF_TEXTWRAP = $08; { Exported functions @@ -392,6 +396,7 @@ var lBorders: TsCellBorders; lAddBackground: Boolean; lBackgroundColor: TsColor; + lWordWrap: Boolean; fmt: String; begin // The first 4 styles were already added @@ -402,7 +407,6 @@ begin lFormatIndex := 0; //General format (one of the built-in number formats) lTextRotation := XF_ROTATION_HORIZONTAL; lBorders := []; - lAddBackground := False; lBackgroundColor := FFormattingStyles[i].BackgroundColor; // Now apply the modifications. @@ -480,11 +484,12 @@ begin if uffBold in FFormattingStyles[i].UsedFormattingFields then lFontIndex := 1; - if uffBackgroundColor in FFormattingStyles[i].UsedFormattingFields then - lAddBackground := True; + lAddBackground := (uffBackgroundColor in FFormattingStyles[i].UsedFormattingFields); + lWordwrap := (uffWordwrap in FFormattingStyles[i].UsedFormattingFields); // And finally write the style - WriteXF(AStream, lFontIndex, lFormatIndex, 0, lTextRotation, lBorders, lAddBackground, lBackgroundColor); + WriteXF(AStream, lFontIndex, lFormatIndex, 0, lTextRotation, lBorders, lWordwrap, + lAddBackground, lBackgroundColor); end; end; @@ -1520,7 +1525,8 @@ end; *******************************************************************} procedure TsSpreadBIFF8Writer.WriteXF(AStream: TStream; AFontIndex: Word; AFormatIndex: Word; AXF_TYPE_PROT, ATextRotation: Byte; ABorders: TsCellBorders; - AddBackground: Boolean = False; ABackgroundColor: TsColor = scSilver); + AddWordWrap: Boolean = false; AddBackground: Boolean = false; + ABackgroundColor: TsColor = scSilver); var XFOptions: Word; XFAlignment, XFOrientationAttrib: Byte; @@ -1546,6 +1552,8 @@ begin { Alignment and text break } XFAlignment := MASK_XF_VERT_ALIGN_BOTTOM; + if AddWordWrap then + XFAlignment := XFAlignment or MASK_XF_TEXTWRAP; AStream.WriteByte(XFAlignment); @@ -2050,6 +2058,12 @@ begin if Assigned(lCell) then begin XFData := TXFRecordData(FXFList.Items[XFIndex]); + // Word wrap + if XFData.WordWrap then + Include(lCell^.UsedFormattingFields, uffWordWrap) + else + Exclude(lCell^.UsedFormattingFields, uffWordWrap); + // Borders if XFData.Borders <> [] then begin Include(lCell^.UsedFormattingFields, uffBorder); @@ -2389,6 +2403,9 @@ begin // Format index lData.FormatIndex := WordLEToN(xf.FormatIndex); + // Word wrap + lData.WordWrap := (xf.Align_TextBreak and MASK_XF_TEXTWRAP) <> 0; + // Cell borders xf.Border_Background_1 := DWordLEToN(xf.Border_Background_1); lData.Borders := [];