LazReport: fixes and improvements on spreadsheet exporters, patch from Aleksey Lagunov

1. Improved speed on export 
2. Fix export vertical merged cells
3. Add filter in save reports dialog for export to MS Excel 2007/2010
4. Fix scale factor on export - use hard coded const 
5. Replace array to TfpList for register export filters
6. Add code for disable export filters in run-time
7. In report designer fix FileName property on preview report

git-svn-id: trunk@49728 -
This commit is contained in:
jesus 2015-08-30 17:38:01 +00:00
parent bec0723351
commit 400b4c4719
7 changed files with 298 additions and 71 deletions

View File

@ -220,11 +220,11 @@ var
FEmailApp:TEmailApp;
begin
FilterClass:=nil;
for i:=0 to frFiltersCount - 1 do
if (frFilters[i].FilterDesc = AttachmentFormat) then
for i:=0 to ExportFilters.Count - 1 do
if (ExportFilters[i].FilterDesc = AttachmentFormat) then
begin
FilterClass := frFilters[i].ClassRef;
SExt:=ExtractFileExt(frFilters[i].FilterExt);
FilterClass := ExportFilters[i].ClassRef;
SExt:=ExtractFileExt(ExportFilters[i].FilterExt);
break;
end;
if not Assigned(FilterClass) then exit;

View File

@ -138,8 +138,9 @@ var
i: Integer;
begin
cbFilterList.Items.Clear;
for i:=0 to frFiltersCount-1 do
cbFilterList.Items.Add(frFilters[i].FilterDesc);
for i:=0 to ExportFilters.Count - 1 do
if ExportFilters[i].Enabled then
cbFilterList.Items.Add(ExportFilters[i].FilterDesc);
if (cbFilterList.Items.Count>0) and (FEmailExport.AttachmentFormat<>'') then
if cbFilterList.Items.IndexOf(FEmailExport.AttachmentFormat)>-1 then

View File

@ -57,11 +57,14 @@ type
FWorksheet:TsWorksheet;
FFileName:string;
FCurPage:integer;
FTmpTextWidth: Integer;
FTmpTextHeight: Integer;
{ FTmpTextWidth: Integer;
FTmpTextHeight: Integer;}
FTmpTextWidth: Double;
FTmpTextHeight: Double;
procedure ExportColWidth;
procedure ExportRowHight;
procedure ExportData;
//procedure ExportData;
procedure ExportData1;
procedure MakeWorksheet;
protected
@ -109,7 +112,8 @@ var
begin
for i:=0 to FExportMatrix.ColumnCount-1 do
//FWorksheet.WriteColWidth(i, round(FExportMatrix.ColumnWidth[i] * 0.161404639));
FWorksheet.WriteColWidth(i, Max(FExportMatrix.ColumnWidth[i] div FTmpTextWidth, 1));
//FWorksheet.WriteColWidth(i, Max(FExportMatrix.ColumnWidth[i] / FTmpTextWidth, 1));
FWorksheet.WriteColWidth(i, FExportMatrix.ColumnWidth[i] / FTmpTextWidth);
end;
procedure TlrSpreadSheetExportFilter.ExportRowHight;
@ -117,16 +121,9 @@ var
i: Integer;
begin
for i:=0 to FExportMatrix.RowCount - 1 do
FWorksheet.WriteRowHeight(i, FExportMatrix.RowHiht[i] div FTmpTextHeight);
FWorksheet.WriteRowHeight(i, FExportMatrix.RowHiht[i] / FTmpTextHeight);
end;
procedure TlrSpreadSheetExportFilter.ExportData;
var
R:TExportObject;
y: Integer;
x: Integer;
scFrm:TsCellBorders;
function sftofs(AFont:TFont):TsFontStyles;
begin
Result:=[];
@ -142,6 +139,13 @@ begin
if fsUnderline in AFont.Style then
Result:=Result + [fssUnderline];
end;
{
procedure TlrSpreadSheetExportFilter.ExportData;
var
R:TExportObject;
y: Integer;
x: Integer;
scFrm:TsCellBorders;
begin
for y:=0 to FExportMatrix.RowCount do
@ -195,6 +199,74 @@ begin
end;
end;
end;
}
procedure TlrSpreadSheetExportFilter.ExportData1;
var
R: Integer;
Row: TExportRow;
C: Integer;
Cel: TExportObject;
X: Integer;
Y: Integer;
scFrm:TsCellBorders;
begin
for R:=0 to FExportMatrix.Rows.Count-1 do
begin
Row:=TExportRow(FExportMatrix.Rows[R]);
for C:=0 to Row.Cells.Count-1 do
begin
Cel:=TExportObject(Row.Cells[C]);
if Assigned(Cel) then
begin
X:=Cel.Col;
Y:=Row.Row;
if Cel.Text<>'' then
begin
FWorksheet.WriteUTF8Text(Y, X, TrimRight(Cel.Texts.Text));
if Cel.Angle <> 0 then
FWorksheet.WriteTextRotation(Y, X, rt90DegreeCounterClockwiseRotation);
FWorksheet.WriteVertAlignment(Y, X, ssLayout[Cel.Layout]);
FWorksheet.WriteWordwrap(Y, X, Cel.WordWrap);
end;
FWorksheet.WriteBackgroundColor(Y, X, Cel.FillColor);
if (Cel.Col < Cel.MergedCol) or (Cel.Row < Cel.MergedRow) then
FWorksheet.MergeCells(Y, X, Cel.MergedRow, Cel.MergedCol);
if Assigned(Cel.Font) then
FWorksheet.WriteFont(Y, X, Cel.Font.Name, Cel.Font.Size, sftofs(Cel.Font), Cel.Font.Color, fpNormal);
FWorksheet.WriteHorAlignment(Y, X, ssAligns[Cel.Alignment]);
scFrm:=[];
if frbLeft in Cel.Frames then
begin
FWorksheet.WriteBorderColor(Y, X, cbEast, Cel.FrameColor);
scFrm:=scFrm + [cbEast]
end;
if frbTop in Cel.Frames then
begin
FWorksheet.WriteBorderColor(Y, X, cbNorth, Cel.FrameColor);
scFrm:=scFrm + [cbNorth]
end;
if frbBottom in Cel.Frames then
begin
FWorksheet.WriteBorderColor(Y, X, cbSouth, Cel.FrameColor);
scFrm:=scFrm + [cbSouth]
end;
if frbRight in Cel.Frames then
begin
FWorksheet.WriteBorderColor(Y, X, cbWest, Cel.FrameColor);
scFrm:=scFrm + [cbWest]
end;
if scFrm <> [] then
FWorksheet.WriteBorders(Y, X, scFrm);
end;
end;
end;
end;
procedure TlrSpreadSheetExportFilter.MakeWorksheet;
var
@ -209,7 +281,8 @@ begin
FWorksheet := FWorkbook.AddWorksheet(S);
ExportColWidth;
ExportRowHight;
ExportData;
//ExportData;
ExportData1;
FWorksheet:=nil;
FExportMatrix.Clear;
end;
@ -318,8 +391,12 @@ end;
procedure TlrSpreadSheetExportFilter.OnBeginDoc;
begin
inherited OnBeginDoc;
FTmpTextWidth:=(TempBmp.Canvas.TextWidth('W') + TempBmp.Canvas.TextWidth('i')) div 2;
FTmpTextHeight:=TempBmp.Canvas.TextHeight('Wg');
// FTmpTextWidth:=(TempBmp.Canvas.TextWidth('W') + TempBmp.Canvas.TextWidth('i')) div 2;
// FTmpTextWidth:=TempBmp.Canvas.TextWidth('Wi') / 2;
{ FTmpTextWidth:=TempBmp.Canvas.TextWidth('I');
FTmpTextHeight:=TempBmp.Canvas.TextHeight('Wg');}
FTmpTextWidth:=7;
FTmpTextHeight:=12;
FWorkbook := TsWorkbook.Create;
FCurPage:=0;
end;
@ -351,6 +428,7 @@ end;
initialization
frRegisterExportFilter(TlrSpreadSheetExportFilter, 'Microsoft Excel (*.xls)', '*.xls');
frRegisterExportFilter(TlrSpreadSheetExportFilter, 'Microsoft Excel 2007/2010 (*.xlsx)', '*.xlsx');
frRegisterExportFilter(TlrSpreadSheetExportFilter, 'OpenOffice/LibreOffice (*.ods)', '*.ods');
end.

View File

@ -116,6 +116,8 @@ type
property Top:integer read FTop write FTop;
property Row:integer read FRow;
property Cells:TFpList read FCells;
end;
{ TExportMatrix }
@ -160,6 +162,8 @@ type
property DeleteEmptyRow:boolean read FDeleteEmptyRow write FDeleteEmptyRow;
property MergeCell:boolean read FMergeCell write FMergeCell;
property PageMargin:integer read FPageMargin write FPageMargin;
property Rows:TFpList read FRows;
end;
implementation
@ -523,7 +527,7 @@ begin
for j:=0 to TExportRow(FRows[i]).FCells.Count - 1 do
begin
FObj:=TExportObject(TExportRow(FRows[i]).FCells[j]);
FObj.FRow:=i;
// FObj.FRow:=i;
FObj.FCol:=GetColNumByLeft(FObj.FLeft);
end;
end;

View File

@ -1498,11 +1498,43 @@ type
EditorProc : TlrObjEditorProc;
end;
TfrExportFilterInfo = record
ClassRef: TfrExportFilterClass;
FilterDesc, FilterExt: String;
{ TExportFilterItem }
TExportFilterItem = class
private
FClassRef: TfrExportFilterClass;
FEnabled: boolean;
FFilterDesc: String;
FFilterExt: String;
public
constructor Create;
property ClassRef: TfrExportFilterClass read FClassRef;
property FilterDesc: String read FFilterDesc;
property FilterExt: String read FFilterExt;
property Enabled:boolean read FEnabled write FEnabled;
end;
{ TExportFilters }
TExportFilters = class
private
FList:TFPList;
function GetCount: integer;
procedure Clear;
function GetItems(AItem: Integer): TExportFilterItem;
public
constructor Create;
destructor Destroy; override;
procedure RegisterFilter(AClassRef: TfrExportFilterClass; const AFilterDesc, AFilterExt: String);
procedure DisableFilter(AFilterExt: String);
procedure EnableFilter(AFilterExt: String);
function FindFilter(AFilterExt: String):TExportFilterItem;
function FilterIndex(AClassRef: TfrExportFilterClass; AFilterExt:string): Integer;
property Count:integer read GetCount;
property Items[AItem:Integer]:TExportFilterItem read GetItems;default;
end;
TfrFunctionInfo = record
FunctionLibrary: TfrFunctionLibrary;
end;
@ -1529,8 +1561,6 @@ var
DisableDrawing: Boolean;
frAddIns: Array[0..31] of TfrAddInObjectInfo; // add-in objects
frAddInsCount: Integer;
frFilters: Array[0..31] of TfrExportFilterInfo; // export filters
frFiltersCount: Integer;
frFunctions: Array[0..31] of TfrFunctionInfo; // function libraries
frFunctionsCount: Integer;
frTools: Array[0..31] of TfrToolsInfo; // tools
@ -1557,6 +1587,7 @@ var
// variables used through report building
TempBmp: TBitmap; // temporary bitmap used by TfrMemoView
function ExportFilters:TExportFilters;
implementation
uses
@ -1607,6 +1638,7 @@ var
AppendPage, WasPF: Boolean;
CompositeMode: Boolean;
MaxTitleSize: Integer = 0;
FExportFilters:TExportFilters = nil;
{-----------------------------------------------------------------------------}
@ -1741,6 +1773,13 @@ begin
end;
end;
function ExportFilters: TExportFilters;
begin
if not Assigned(FExportFilters) then
FExportFilters:=TExportFilters.Create;
Result:=FExportFilters;
end;
function DoFindObjMetod(S: string; out AObjProp: string
): TfrObject;
begin
@ -1902,20 +1941,6 @@ begin
end;
end;
function frGetExportFilterIndex(AClassRef: TfrExportFilterClass; const AFilterExt:string): Integer;
var
i: Integer;
begin
result := -1;
for i:=0 to Length(frFilters)-1 do
with frFilters[i] do
if (ClassRef=AClassRef) and (FilterExt=AFilterExt) then
begin
result := i;
break;
end;
end;
procedure frSetAddinEditor(ClassRef: TfrViewClass; EditorForm: TfrObjEditorForm);
var
i: Integer;
@ -1952,13 +1977,7 @@ end;
procedure frRegisterExportFilter(ClassRef: TfrExportFilterClass;
const FilterDesc, FilterExt: String);
begin
if frGetExportFilterIndex(ClassRef, FilterExt)<0 then
begin
frFilters[frFiltersCount].ClassRef := ClassRef;
frFilters[frFiltersCount].FilterDesc := FilterDesc;
frFilters[frFiltersCount].FilterExt := FilterExt;
Inc(frFiltersCount);
end;
ExportFilters.RegisterFilter(ClassRef, FilterDesc, FilterExt);
end;
procedure frRegisterFunctionLibrary(ClassRef: TClass);
@ -2112,6 +2131,109 @@ begin
DebugLn('Error: ', e.message,'. Hyphenation support will be disabled');
end;
end;
{ TExportFilterItem }
constructor TExportFilterItem.Create;
begin
inherited Create;
FEnabled:=true;
end;
{ TExportFilters }
function TExportFilters.GetCount: integer;
begin
Result:=FList.Count;
end;
procedure TExportFilters.Clear;
var
i: Integer;
begin
for i:=0 to FList.Count-1 do
TExportFilterItem(FList[i]).Free;
FList.Clear;
end;
function TExportFilters.GetItems(AItem: Integer): TExportFilterItem;
begin
Result:=TExportFilterItem(FList[AItem]);
end;
constructor TExportFilters.Create;
begin
inherited Create;
FList:=TFPList.Create;
end;
destructor TExportFilters.Destroy;
begin
Clear;
inherited Destroy;
end;
procedure TExportFilters.RegisterFilter(AClassRef: TfrExportFilterClass;
const AFilterDesc, AFilterExt: String);
var
F: TExportFilterItem;
begin
if FilterIndex(AClassRef, AFilterExt) > -1 then exit;
F:=TExportFilterItem.Create;
F.FClassRef:=AClassRef;
F.FFilterExt:=AFilterExt;
F.FFilterDesc:=AFilterDesc;
FList.Add(F);
end;
procedure TExportFilters.DisableFilter(AFilterExt: String);
var
F: TExportFilterItem;
begin
F:=FindFilter(AFilterExt);
if Assigned(F) then
F.FEnabled:=true;
end;
procedure TExportFilters.EnableFilter(AFilterExt: String);
var
F: TExportFilterItem;
begin
F:=FindFilter(AFilterExt);
if Assigned(F) then
F.FEnabled:=false;
end;
function TExportFilters.FindFilter(AFilterExt: String): TExportFilterItem;
var
i: Integer;
begin
Result:=nil;
AFilterExt:=UTF8UpperCase(AFilterExt);
for i:=0 to FList.Count-1 do
if UTF8UpperCase(TExportFilterItem(FList[i]).FFilterExt) = AFilterExt then
begin
Result:=TExportFilterItem(FList[i]);
exit;
end;
end;
function TExportFilters.FilterIndex(AClassRef: TfrExportFilterClass;
AFilterExt: string): Integer;
var
i: Integer;
begin
Result:=-1;
AFilterExt:=UTF8UpperCase(AFilterExt);
for i:=0 to FList.Count-1 do
if (TExportFilterItem(FList[i]).FClassRef = AClassRef) and (TExportFilterItem(FList[i]).FilterExt = AFilterExt) then
begin
Result:=i;
exit;
end;
end;
{
procedure CanvasTextRectJustify(const Canvas:TCanvas;
const ARect: TRect; X1, X2, Y: integer; const Text: string;
@ -10836,10 +10958,10 @@ begin
// try to find a export filter from registered list
if (FilterClass=nil) and (fDefExportFilterClass<>'') then
begin
for i:=0 to Length(frFilters)-1 do
if (frFilters[i].ClassRef.ClassName=fDefExportFilterClass) then
for i:=0 to ExportFilters.Count - 1 do
if (ExportFilters[i].FClassRef.ClassName=fDefExportFilterClass) then
begin
FilterClass := frFilters[i].ClassRef;
FilterClass := ExportFilters[i].FClassRef;
break;
end;
end;
@ -12605,6 +12727,8 @@ begin
frVariables.Free;
frCompressor.Free;
HookList.Free;
if Assigned(FExportFilters) then
FreeAndNil(FExportFilters);
end;
{ TfrObject }

View File

@ -3338,6 +3338,7 @@ begin
try
Rep.LoadFromXMLStream(TestRepStream);
Rep.FileName:=SaveR.FileName;
Rep.ShowReport;
FreeAndNil(Rep)
except

View File

@ -438,8 +438,9 @@ var
begin
result := false;
AExt := ExtractFileExt(AFileName);
for i:=0 to frFiltersCount-1 do
if SameText(AExt, ExtractFileExt(frFilters[i].FilterExt)) then begin
for i:=0 to ExportFilters.Count - 1 do
if SameText(AExt, ExtractFileExt(ExportFilters[i].FilterExt)) then
begin
FWindow.ExportToWithFilterIndex(i, AFileName);
result := true;
break;
@ -706,8 +707,7 @@ begin
begin
FindBtn.Visible := pbFind in TfrReport(Doc).PreviewButtons;
ZoomBtn.Visible := pbZoom in TfrReport(Doc).PreviewButtons;
SaveBtn.Visible := (pbSave in TfrReport(Doc).PreviewButtons) and not
((frFiltersCount = 0) and (roHideDefaultFilter in TfrReport(Doc).Options));
SaveBtn.Visible := (pbSave in TfrReport(Doc).PreviewButtons) and not ((ExportFilters.Count = 0) and (roHideDefaultFilter in TfrReport(Doc).Options));
LoadBtn.Visible := pbLoad in TfrReport(Doc).PreviewButtons;
PrintBtn.Visible := pbPrint in TfrReport(Doc).PreviewButtons;
ExitBtn.Visible := pbExit in TfrReport(Doc).PreviewButtons;
@ -885,10 +885,10 @@ end;
function TfrPreviewForm.ExportToWithFilterIndex(AFilterIndex: Integer;
const AFileName: string):boolean;
begin
if (AFilterIndex<0) or (AFilterIndex>=frFiltersCount) then
if (AFilterIndex<0) or (AFilterIndex>=ExportFilters.Count) then
raise exception.Create(sExportFilterIndexError);
ConnectBack;
TfrReport(Doc).ExportTo(frFilters[AFilterIndex].ClassRef, AFileName);
TfrReport(Doc).ExportTo(ExportFilters[AFilterIndex].ClassRef, AFileName);
Connect(Doc);
Result:=true;
end;
@ -1349,12 +1349,15 @@ procedure TfrPreviewForm.SaveBtnClick(Sender: TObject);
var
i, Index, IndexOffset: Integer;
FilterStr, FilterExtension, FileExtension: String;
FilterInfo: TfrExportFilterInfo;
FilterInfo: TExportFilterItem;
FExtList:TStringList;
begin
if EMFPages = nil then Exit;
FExtList:=TStringList.Create;
Index := 1;
if not (roHideDefaultFilter in TfrReport(Doc).Options) then
begin
FExtList.Add('*.frp');
FilterStr := sRepFile + ' (*.frp)|*.frp';
IndexOffset := 2;
end
@ -1364,30 +1367,46 @@ begin
IndexOffset := 1;
end;
FileExtension := ExtractFileExt(SaveDialog.FileName);
for i := 0 to frFiltersCount - 1 do
for i := 0 to ExportFilters.Count - 1 do
begin
FilterInfo := frFilters[i];
if FilterStr <> '' then
FilterStr := FilterStr + '|';
FilterStr := FilterStr + FilterInfo.FilterDesc + '|' + FilterInfo.FilterExt;
FilterExtension := ExtractFileExt(FilterInfo.FilterExt);
if (Index = 1) and (Comparetext(FilterExtension, FileExtension)=0) then
Index := i + IndexOffset;
FilterInfo := ExportFilters[i];
if FilterInfo.Enabled then
begin
FExtList.Add(FilterInfo.FilterExt);
if FilterStr <> '' then
FilterStr := FilterStr + '|';
FilterStr := FilterStr + FilterInfo.FilterDesc + '|' + FilterInfo.FilterExt;
FilterExtension := ExtractFileExt(FilterInfo.FilterExt);
if (Index = 1) and (Comparetext(FilterExtension, FileExtension)=0) then
Index := i + IndexOffset;
end;
end;
SaveDialog.Filter := FilterStr;
SaveDialog.FilterIndex := Index;
if SaveDialog.Execute then
begin
Index := SaveDialog.FilterIndex - IndexOffset;
if Index = -1 then
FileExtension:=ExtractFileExt(SaveDialog.FileName);
if FileExtension = '' then
FileExtension:=UTF8Copy(FExtList[SaveDialog.FilterIndex - 1], 2, UTF8Length(FExtList[SaveDialog.FilterIndex - 1]) - 1);
if FileExtension = '.frp' then
SaveToFile(SaveDialog.FileName)
else
begin
FilterExtension := Copy(frFilters[Index].FilterExt, 2, 255);
ExportToWithFilterIndex(Index,
ChangeFileExt(SaveDialog.FileName, FilterExtension));
for i := 0 to ExportFilters.Count - 1 do
begin
FilterInfo := ExportFilters[i];
if FilterInfo.Enabled and (FileExtension = UTF8Copy(FilterInfo.FilterExt, 2, UTF8Length(FilterInfo.FilterExt) - 1)) then
begin
ExportToWithFilterIndex(i, ChangeFileExt(SaveDialog.FileName, FileExtension));
break;
end;
end;
end;
end;
FExtList.Free;
end;
procedure TfrPreviewForm.PrintBtnClick(Sender: TObject);