BSOne.SFC/Tocsg.Lib/VCL/Tocsg.Export.pas

666 lines
19 KiB
Plaintext

{*******************************************************}
{ }
{ Tocsg.Export }
{ }
{ Copyright (C) 2023 kku }
{ }
{*******************************************************}
unit Tocsg.Export;
interface
uses
System.SysUtils, Winapi.Windows, System.Classes, Winapi.ActiveX, VirtualTrees;
const
xlCsv = 6;
xlXls = 43;
xlHtml = 44;
xlNxl = -2003;
xlCell = -4143;
xlText = -4158;
xlLeft = -4131;
xlRight = -4152;
xlCenter = -4108;
xlQualityStandard = $00000000;
xlQualityMinimum = $00000001;
xlTypePDF = $00000000;
xlTypeXPS = $00000001;
type
TFnExportExpert = reference to procedure(vExcel: Variant);
XlFixedFormatType = TOleEnum;
XlFixedFormatQuality = TOleEnum;
TExportTargetKind = (etkAll, etkSelected, etkChecked);
function ExportCSV_VT(vt: TVirtualStringTree; sExportPath: String;
aEncoding: TEncoding; aExpTgKind: TExportTargetKind = etkAll; pRootNode: PVirtualNode = nil): Boolean;
function ExportCSV_VT_Div(vt: TVirtualStringTree; sExportPath: String;
aEncoding: TEncoding; nDivCount: Integer; aExpTgKind: TExportTargetKind = etkAll; bHitsCount: Boolean = false): Boolean;
function ExportXLS_VT(vt: TVirtualStringTree; const sSheetCaption, sExportPath: String;
FnExportExpert: TFnExportExpert = nil; aExpTgKind: TExportTargetKind = etkAll): Boolean;
function ExportXLS_VT_Div(vt: TVirtualStringTree; const sSheetCaption, sExportPath: String; nDivCount: Integer;
FnExportExpert: TFnExportExpert = nil; aExpTgKind: TExportTargetKind = etkAll): Boolean;
function ExportHanCell_VT(vt: TVirtualStringTree; const sSheetCaption, sExportPath: String;
aExpTgKind: TExportTargetKind = etkAll): Boolean;
function ExportXlsFromCsv(const sCsvPath, sOutPath: String; aCsvEncoding: TEncoding): Boolean;
implementation
uses
System.Win.ComObj, System.Variants, Vcl.Graphics, Tocsg.Safe, Tocsg.Exception,
Tocsg.VTUtil, VirtualTrees.Types, Tocsg.Strings, Tocsg.Path;
function ExportCSV_VT(vt: TVirtualStringTree; sExportPath: String;
aEncoding: TEncoding; aExpTgKind: TExportTargetKind = etkAll; pRootNode: PVirtualNode = nil): Boolean;
var
pNode: PVirtualNode;
StrList: TStringList;
sData: String;
i: Integer;
begin
Result := false;
Guard(StrList, TStringList.Create);
sData := '';
for i := 0 to vt.Header.Columns.Count - 1 do
begin
if coVisible in vt.Header.Columns[i].Options then
SumString(sData, '"' + vt.Header.Columns[i].Text + '"', ',');
end;
StrList.Add(sData);
case aExpTgKind of
etkAll : pNode := vt.GetFirst;
etkSelected : pNode := vt.GetFirstSelected;
etkChecked : pNode := vt.GetFirstChecked;
else pNOde := nil;
end;
while pNode <> nil do
begin
sData := '';
if (pRootNode = nil) or (pRootNode = pNode.Parent) then
begin
for i := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[i].Options then
SumString(sData, '"' + StringReplace(vt.Text[pNode, i], '"', '', [rfReplaceAll]) + '"', ',');
if sData <> '' then
StrList.Add(sData);
end;
case aExpTgKind of
etkAll : pNode := vt.GetNext(pNode);
etkSelected : pNode := vt.GetNextSelected(pNode);
etkChecked : pNode := vt.GetNextChecked(pNode);
end;
end;
if GetFileExt(sExportPath).ToUpper <> 'CSV' then
sExportPath := sExportPath + '.csv';
StrList.SaveToFile(sExportPath, aEncoding);
Result := true;
end;
function ExportCSV_VT_Div(vt: TVirtualStringTree; sExportPath: String;
aEncoding: TEncoding; nDivCount: Integer; aExpTgKind: TExportTargetKind = etkAll; bHitsCount: Boolean = false): Boolean;
var
pNode: PVirtualNode;
StrList: TStringList;
sExt,
sExcludeExtPath,
sSavePath,
sData: String;
i, nFileNum,
nAddedCnt: Integer;
procedure InitData;
var
c: Integer;
begin
nAddedCnt := 0;
StrList.Clear;
sData := '';
for c := 0 to vt.Header.Columns.Count - 1 do
begin
if coVisible in vt.Header.Columns[c].Options then
SumString(sData, vt.Header.Columns[c].Text, ',');
end;
StrList.Add(sData);
end;
procedure SaveData;
begin
Inc(nFileNum);
sSavePath := Format('%s - %.3d%s', [sExcludeExtPath, nFileNum, sExt]);
StrList.SaveToFile(sSavePath, aEncoding);
InitData;
end;
begin
Result := false;
if GetFileExt(sExportPath).ToUpper <> 'CSV' then
sExportPath := sExportPath + '.csv';
sExt := ExtractFileExt(sExportPath);
sExcludeExtPath := CutFileExt(sExportPath);
nFileNum := 0;
case aExpTgKind of
etkAll : pNode := vt.GetFirst;
etkSelected : pNode := vt.GetFirstSelected;
etkChecked : pNode := vt.GetFirstChecked;
else pNode := nil;
end;
Guard(StrList, TStringList.Create);
InitData;
while pNode <> nil do
begin
sData := '';
for i := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[i].Options then
SumString(sData, '"' + StringReplace(vt.Text[pNode, i], '"', '', [rfReplaceAll]) + '"', ',');
if sData <> '' then
begin
StrList.Add(sData);
Inc(nAddedCnt);
if nAddedCnt >= nDivCount then
SaveData;
end;
case aExpTgKind of
etkAll : pNode := vt.GetNext(pNode);
etkSelected : pNode := vt.GetNextSelected(pNode);
etkChecked : pNode := vt.GetNextChecked(pNode);
end;
end;
if nAddedCnt > 0 then
SaveData;
Result := true;
end;
function ExportXLS_VT(vt: TVirtualStringTree; const sSheetCaption, sExportPath: String; FnExportExpert: TFnExportExpert = nil; aExpTgKind: TExportTargetKind = etkAll): Boolean;
var
vExcel, vWorkBook: Variant;
vArrData: OleVariant;
i, nRow, nCol: Integer;
pNode: PVirtualNode;
dwRecordCnt,
dwColumnCnt: DWORD;
ClassID: TCLSID;
begin
Result := false;
if not Succeeded(CLSIDFromProgID(PWideChar(WideString('Excel.Application')), ClassID)) then
exit;
try
vExcel := CreateOleObject('Excel.Application');
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportXLS_VT() .. fail CreateOleObject(Excel.Application) ..');
exit;
end;
end;
try
try
vWorkBook := vExcel.WorkBooks.Add;
if Assigned(FnExportExpert) then
FnExportExpert(vExcel);
dwRecordCnt := 0;
case aExpTgKind of
etkAll : dwRecordCnt := VT_CountTotalNode(vt);
etkSelected : dwRecordCnt := vt.SelectedCount;
etkChecked : dwRecordCnt := VT_CountVisibleCheckedNode(vt);
end;
// 엑셀 내보내기는 60000 미만으로 해야한다
if dwRecordCnt > 60000 then
exit;
dwColumnCnt := 0;
for nCol := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[nCol].Options then
Inc(dwColumnCnt);
nRow := 0;
vArrData := VarArrayCreate([0, dwRecordCnt, 0, dwColumnCnt - 1], varVariant);
i := 0;
for nCol := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[nCol].Options then
begin
vArrData[nRow, i] := vt.Header.Columns[nCol].Text;
Inc(i);
end;
case aExpTgKind of
etkAll : pNode := vt.GetFirst;
etkSelected : pNode := vt.GetFirstSelected;
etkChecked : pNode := vt.GetFirstChecked;
else pNode := nil;
end;
while pNode <> nil do
begin
Inc(nRow);
i := 0;
for nCol := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[nCol].Options then
begin
vArrData[nRow, i] := vt.Text[pNode, nCol];
Inc(i);
end;
case aExpTgKind of
etkAll : pNode := vt.GetNext(pNode);
etkSelected : pNode := vt.GetNextSelected(pNode);
etkChecked : pNode := vt.GetNextChecked(pNode);
end;
end;
vWorkBook := vExcel.WorkSheets.Add;
vExcel.Sheets[1].Name := DeleteChars(':\/?*[]', sSheetCaption);
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[1, dwColumnCnt]].Select;
vExcel.Selection.Interior.ColorIndex := 15;
vExcel.Selection.Interior.Pattern := 1;
vExcel.Selection.Borders.LineStyle := 1;
vExcel.Selection.Font.Name := 'Tahoma';//'굴림';
vExcel.Selection.Font.Size := 10;
vExcel.Selection.Font.Bold := True;
vExcel.Selection.Font.Color := clBlack;
// 가로 타이틀 정렬
vExcel.Selection.VerticalAlignment := 2;
vExcel.Selection.HorizontalAlignment := 3;
vExcel.Range[vExcel.Cells[2, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.Font.Size := 10;
vExcel.Selection.Font.Name := 'Tahoma';//'굴림';
vExcel.Selection.VerticalAlignment := 1;
vExcel.Selection.HorizontalAlignment := 1;
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].NumberFormatLocal := WideString('@'); // 문자열 강제 지정
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Value := vArrData;
vExcel.Range[vExcel.Cells[2, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.VerticalAlignment := 2;
vExcel.Selection.HorizontalAlignment := 2;
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.Columns.AutoFit;
finally
vExcel.DisplayAlerts := False;
vExcel.Visible := False;
vWorkBook.Saveas(sExportPath);
// vWorkBook.ExportAsFixedFormat(xlTypePDF, sExportPath);
vExcel.Quit;
vExcel := Unassigned;
end;
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportXLS_VT() ..');
exit;
end;
end;
Result := true;
end;
function ExportXLS_VT_Div(vt: TVirtualStringTree; const sSheetCaption, sExportPath: String; nDivCount: Integer; FnExportExpert: TFnExportExpert = nil; aExpTgKind: TExportTargetKind = etkAll): Boolean;
var
vExcel, vWorkBook: Variant;
vArrData: OleVariant;
i, nRow, nCol, nFileNum: Integer;
pNode: PVirtualNode;
dwRecordCnt,
dwColumnCnt: DWORD;
sExt,
sSavePath,
sExcludeExtPath: String;
function InitData: Boolean;
var
c: Integer;
begin
Result := false;
try
vExcel := CreateOleObject('Excel.Application');
except
on E: Exception do
begin
ETgException.TraceException(E, 'Fail .. ExportXLS_VT_Div() .. fail CreateOleObject(Excel.Application) ..');
exit;
end;
end;
try
vWorkBook := vExcel.WorkBooks.Add;
if Assigned(FnExportExpert) then
FnExportExpert(vExcel);
case aExpTgKind of
etkAll : dwRecordCnt := VT_CountTotalNode(vt);
etkSelected : dwRecordCnt := vt.SelectedCount;
etkChecked : dwRecordCnt := VT_CountVisibleCheckedNode(vt);
end;
dwColumnCnt := 0;
for c := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[c].Options then
Inc(dwColumnCnt);
nRow := 0;
vArrData := VarArrayCreate([0, dwRecordCnt, 0, dwColumnCnt - 1], varVariant);
i := 0;
for c := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[c].Options then
begin
vArrData[nRow, i] := vt.Header.Columns[c].Text;
Inc(i);
end;
except
on E: Exception do
begin
ETgException.TraceException(E, 'Fail .. ExportXLS_VT_Div() .. InitData()');
exit;
end;
end;
Result := true;
end;
function SaveData: Boolean;
begin
vWorkBook := vExcel.WorkSheets.Add;
vExcel.Sheets[1].Name := DeleteChars(':\/?*[]', sSheetCaption);
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[1, dwColumnCnt]].Select;
vExcel.Selection.Interior.ColorIndex := 15;
vExcel.Selection.Interior.Pattern := 1;
vExcel.Selection.Borders.LineStyle := 1;
vExcel.Selection.Font.Name := 'Tahoma';//'굴림';
vExcel.Selection.Font.Size := 10;
vExcel.Selection.Font.Bold := True;
vExcel.Selection.Font.Color := clBlack;
// 가로 타이틀 정렬
vExcel.Selection.VerticalAlignment := 2;
vExcel.Selection.HorizontalAlignment := 3;
vExcel.Range[vExcel.Cells[2, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.Font.Size := 10;
vExcel.Selection.Font.Name := 'Tahoma';//'굴림';
vExcel.Selection.VerticalAlignment := 1;
vExcel.Selection.HorizontalAlignment := 1;
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].NumberFormatLocal := WideString('@'); // 문자열 강제 지정
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Value := vArrData;
vExcel.Range[vExcel.Cells[2, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.VerticalAlignment := 2;
vExcel.Selection.HorizontalAlignment := 2;
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.Columns.AutoFit;
Inc(nFileNum);
sSavePath := Format('%s - %.3d.%s', [sExcludeExtPath, nFileNum, sExt]);
vExcel.DisplayAlerts := False;
vExcel.Visible := False;
vWorkBook.Saveas(sSavePath);
vExcel.Quit;
vExcel := Unassigned;
Result := InitData;
end;
begin
Result := false;
sExt := ExtractFileExt(sExportPath);
sExcludeExtPath := CutFileExt(sExportPath);
if not InitData then
exit;
try
pNode := nil;
try
case aExpTgKind of
etkAll : pNode := vt.GetFirst;
etkSelected : pNode := vt.GetFirstSelected;
etkChecked : pNode := vt.GetFirstChecked;
end;
while pNode <> nil do
begin
Inc(nRow);
i := 0;
for nCol := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[nCol].Options then
begin
vArrData[nRow, i] := vt.Text[pNode, nCol];
Inc(i);
end;
if nRow >= nDivCount then
if not SaveData then
exit;
case aExpTgKind of
etkAll : pNode := vt.GetNext(pNode);
etkSelected : pNode := vt.GetNextSelected(pNode);
etkChecked : pNode := vt.GetNextChecked(pNode);
end;
end;
if nRow > 1 then
if not SaveData then
exit;
finally
vExcel.Quit;
vExcel := Unassigned;
end;
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportXLS_VT_Div() ..');
exit;
end;
end;
Result := true;
end;
function ExportHanCell_VT(vt: TVirtualStringTree; const sSheetCaption, sExportPath: String; aExpTgKind: TExportTargetKind = etkAll): Boolean;
var
vHancell: OleVariant;
vWorkBook,
vWorkSheet: Variant;
i, nRow, nCol: Integer;
pNode: PVirtualNode;
begin
Result := false;
try
vHancell := CreateOleObject('HCell.Application'); // 한컴 오피스 네오 체험판의 한셀만 설치되어 있다면 작동하지 않음
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportHanCell_VT() .. fail CreateOleObject(HCell.Application) ..');
exit;
end;
end;
try
vHancell.visible := False;
vWorkBook := vHancell.Workbooks.Add;
try
vWorkSheet := vWorkBook.WorkSheets.Add;
except
vWorkSheet := vWorkBook.Sheets.Add;
end;
vWorkSheet.Name := sSheetCaption;
pNode := nil;
try
i := 0;
for nCol := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[nCol].Options then
begin
vWorkSheet.Cells[1, 1 + i].Value := vt.Header.Columns[nCol].Text;
Inc(i);
end;
case aExpTgKind of
etkAll : pNode := vt.GetFirst;
etkSelected : pNode := vt.GetFirstSelected;
etkChecked : pNode := vt.GetFirstChecked;
end;
nRow := 0;
while pNode <> nil do
begin
i := 0;
for nCol := 0 to vt.Header.Columns.Count - 1 do
if coVisible in vt.Header.Columns[nCol].Options then
begin
vWorkSheet.Cells[2 + nRow, 1 + i].Value := vt.Text[pNode, nCol];
Inc(i);
end;
case aExpTgKind of
etkAll : pNode := vt.GetNext(pNode);
etkSelected : pNode := vt.GetNextSelected(pNode);
etkChecked : pNode := vt.GetNextChecked(pNode);
end;
Inc(nRow);
end;
vWorkBook.SaveAs(OleVariant(sExportPath));
finally
vHancell.workbooks.close;
vHancell.Quit;
vHancell := Unassigned;
end;
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportXLS_VT() ..');
exit;
end;
end;
Result := true;
end;
function ExportXlsFromCsv(const sCsvPath, sOutPath: String; aCsvEncoding: TEncoding): Boolean;
var
CsvStrList,
ColumnList: TStringList;
vExcel, vWorkBook: Variant;
vArrData: OleVariant;
i, nRow, nCol: Integer;
dwRecordCnt,
dwColumnCnt: DWORD;
begin
Result := false;
if not FileExists(sCsvPath) then
exit;
Guard(CsvStrList, TStringList.Create);
CsvStrList.LoadFromFile(sCsvPath, aCsvEncoding);
if CsvStrList.Count = 0 then
exit;
Guard(ColumnList, TStringList.Create);
try
vExcel := CreateOleObject('Excel.Application');
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportXLS_fromCVS() .. fail CreateOleObject(Excel.Application) ..');
exit;
end;
end;
try
try
vWorkBook := vExcel.WorkBooks.Add;
dwRecordCnt := CsvStrList.Count;
SplitString2(CsvStrList[CsvStrList.Count-1], ',', ColumnList);
dwColumnCnt := ColumnList.Count;
vArrData := VarArrayCreate([0, dwRecordCnt, 0, dwColumnCnt-1], varVariant);
for nRow := 0 to dwRecordCnt - 1 do
begin
i := 0;
SplitString2(CsvStrList[nRow], ',', ColumnList);
for nCol := 0 to ColumnList.Count - 1 do
begin
vArrData[nRow, i] := ColumnList[nCol];
Inc(i);
end;
end;
vWorkBook := vExcel.WorkSheets.Add;
vExcel.Sheets[1].Name := 'Untitle';
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].NumberFormatLocal := WideString('@'); // 문자열 강제 지정
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Value := vArrData;
vExcel.Range[vExcel.Cells[2, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.VerticalAlignment := 2;
vExcel.Selection.HorizontalAlignment := 2;
vExcel.Range[vExcel.Cells[1, 1], vExcel.Cells[dwRecordCnt + 1, dwColumnCnt]].Select;
vExcel.Selection.Columns.AutoFit;
finally
vExcel.DisplayAlerts := False;
vExcel.Visible := False;
vWorkBook.Saveas(sOutPath);
vExcel.Quit;
vExcel := Unassigned;
end;
except
on E: Exception do
begin
ETgException.TraceException(E, 'ExportXLS_VT() ..');
exit;
end;
end;
Result := true;
end;
end.