Bit late but I updated my Gridview Utils to NextGridUtils.
Besides translation the only new thing is a selected parameter for the CVS routines. I moved the bulk of the code from NG_ExportToCsv to a new funtion called NG_ToCsvString. This to enable clipboarding to excel like:
CODE
var
ls : Char;
begin
ls := ListSeparator;
ListSeparator := #9;
ClipBoard.AsText := NG_ToCsvString(NextGrid1, False, True);
ListSeparator := ls;
ls : Char;
begin
ls := ListSeparator;
ListSeparator := #9;
ClipBoard.AsText := NG_ToCsvString(NextGrid1, False, True);
ListSeparator := ls;
Note without the #9 Excel will paste all into the first column. For cvs files the separator has to be the listseparator.
As usual have fun coding and share it!
CODE
{-----------------------------------------------------------}
{----Purpose : NextGrid utilities }
{ By : Ir. G.W. van der Vegt }
{ For : Myself. }
{ Depends : NextGrid }
{-----------------------------------------------------------}
{ ddmmyyyy comment }
{ -------- ------------------------------------------------ }
{ ddmmyyyy-Initial version }
{ 26052005-Translated to NextGrid. }
{ -Added NG_ToCsvString function. }
{-----------------------------------------------------------}
{ notes: }
{ 1. }
{-----------------------------------------------------------}
{ todo: }
{ 1. }
{-----------------------------------------------------------}
unit NextGridUtils;
interface
uses
NxGrid;
procedure NG_SaveGridLayout(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_RestoreGridLayout(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_SaveGridData(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_RestoreGridData(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_ExportToCsv(const NextGrid: TNextGrid; const fn: string; const header: Boolean = True; const selected: Boolean = False);
function NG_ToCsvString(const NextGrid: TNextGrid; const header: Boolean = True; const selected: Boolean = False): string;
procedure NG_ExportToXml(const NextGrid: TNextGrid; const fn: string);
procedure NG_ImportFromXml(var NextGrid: TNextGrid; const fn: string);
procedure NG_MoveSelectionUp(var NextGrid: TNextGrid);
procedure NG_MoveSelectionDown(var NextGrid: TNextGrid);
procedure NG_AddRowWithValues(var NextGrid: TNextGrid; const columnnames, columnvalues: array of OleVariant);
function NG_LookupValue(const NextGrid: TNextGrid; const lookupcolumnname, lookupvalue, valuecolumnname: OleVariant): OleVariant;
function NG_InserNextGridTable(const NextGrid: TNextGrid): string;
function NG_LocateGrid(const NextGrid: TNextGrid; colnames, values: array of
string): Integer;
function NG_LookupGrid(const NextGrid: TNextGrid; colnames: array of string;
values: array of variant; return: string): string;
implementation
uses
NxCustomGridControl,
NxColumnClasses,
NxColumns,
Classes,
Dialogs,
IniFiles,
StrUtils,
SysUtils,
Variants;
procedure NG_SaveGridLayout(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Section : string;
Layout : TStringList;
i : Integer;
begin
Section := Format('%sLayout', [Prefix]);
with NextGrid do
begin
IniFile := TIniFile.Create(FileName);
IniFile.WriteInteger(section, 'ColumnsCount', Columns.Count);
Layout := TStringList.Create;
for i := 0 to Pred(Columns.Count) do
begin
Layout.Clear;
Layout.Add(IntToStr(Ord(Columns[i].SortKind)));
Layout.Add(IntToStr(Ord(Columns[i].Visible)));
Layout.Add(IntToStr(Ord(Columns[i].Sorted)));
Layout.Add(IntToStr(Ord(Columns[i].Position)));
Layout.Add(IntToStr(Ord(Columns[i].Width)));
Layout.Delimiter := ListSeparator;
IniFile.WriteString(section, Format('Column%d', [i]), Layout.DelimitedText);
end;
IniFile.UpdateFile;
Layout.Free;
IniFile.Free;
end;
end;
procedure NG_RestoreGridLayout(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Layout : TStringList;
Section : string;
Count,
i : Integer;
begin
Section := Format('%sLayout', [Prefix]);
with NextGrid do
begin
IniFile := TIniFile.Create(FileName);
Layout := TStringList.Create;
Count := IniFile.ReadInteger(section, 'ColumnsCount', Columns.Count);
for i := 0 to Pred(Count) do
begin
Layout.Delimiter := ListSeparator;
Layout.DelimitedText := IniFile.ReadString(section, Format('Column%d', [i]), '');
if (Layout.Count = 5) then
begin
Columns[i].SortKind := TSortKind(StrToInt(Layout[0]));
Columns[i].Visible := Boolean(StrToInt(Layout[1]));
Columns[i].Sorted := Boolean(StrToInt(Layout[2]));
Columns[i].Position := StrToInt(Layout[3]);
Columns[i].Width := StrToInt(Layout[4]);
end;
end;
Layout.Free;
IniFile.Free;
end;
end;
procedure NG_ExportToCsv(const NextGrid: TNextGrid; const fn: string; const header: Boolean = True; const selected: Boolean = False);
var
sl : TStringList;
begin
sl := TStringList.Create;
sl.Text := NG_ToCsvString(NextGrid, header, selected);
sl.SaveToFile(fn);
sl.Free;
end;
function NG_ToCsvString(const NextGrid: TNextGrid; const header: Boolean = True; const selected: Boolean = False): string;
{
normalcol;"colwithlistseparator;";"colwithquote"""
1;2;5
4;3;6
}
var
r, c : Integer;
sl : TStringList;
s : string;
function EscapeSeparator(const value: string): string;
begin
if (Pos('"', value) > 0) then
Result := StringReplace(value, '"', '""', [rfReplaceAll])
else
Result := value;
if (Pos(ListSeparator, Result) > 0) or (Pos('""', Result) > 0) then
Result := '"' + Result + '"'
end;
begin
sl := TStringList.Create;
if header then
begin
s := '';
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
if c <> 0 then
s := s + ListSeparator + EscapeSeparator(NextGrid.Columns[c].Header.Caption)
else
s := EscapeSeparator(NextGrid.Columns[c].Header.Caption);
end;
sl.Add(s);
end;
for r := 0 to Pred(NextGrid.RowCount) do
if selected and NextGrid.Selected[r] then
begin
s := '';
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
if c <> 0 then
s := s + ListSeparator + EscapeSeparator(NextGrid.Cell[c, r].AsString)
else
s := EscapeSeparator(NextGrid.Cell[c, r].AsString);
end;
sl.Add(s);
end;
Result := sl.Text;
sl.Free;
end;
procedure NG_ExportToXml(const NextGrid: TNextGrid; const fn: string);
var
r, c : Integer;
sl : TStringList;
function EscapeValue(const value: string): string;
begin
//Not implemented yet.
//Change all characters outside the letters, numbers and crlf to
//< format where 3C is the hex value of the Characters Ord.
Result := value;
end;
begin
sl := TStringList.Create;
sl.Add('<?xml version="1.0"?>');
sl.Add(Format('<NextGrid version = "%s">', ['2.4.1'])); //Should be stVersion!
sl.Add(' <Columns>');
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
//Use Attributes to Export Column Dependend settings like min/max values.
sl.Add(Format(' <Column Name="%s" ColumnClass="%s">', [NextGrid.Columns[c].Name, NextGrid.Columns[c].ClassName]));
sl.Add(' ' + EscapeValue(NextGrid.Columns[c].Header.Caption));
sl.Add(' </Column>');
end;
sl.Add(' </Columns>');
sl.Add(' <Rows>');
for r := 0 to Pred(NextGrid.RowCount) do
begin
sl.Add(' <Row>');
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
sl.Add(' <Cell>');
{if not (NextGrid.Columns[c].ClassNameIs('TGraphicColumn') or
NextGrid.Columns[c].ClassNameIs('TImageColumn')) then}
sl.Add(' ' + EscapeValue(NextGrid.Cell[c, r].AsString));
sl.Add(' </Cell>');
end;
sl.Add(' </Row>');
end;
sl.Add(' </Rows>');
sl.Add('</NextGrid>');
sl.SaveToFile(fn);
sl.Free;
end;
procedure NG_ImportFromXml(var NextGrid: TNextGrid; const fn: string);
var
sl : TStringList;
function FetchAttributes(tag, value: string; var a: TStringList): string;
var
i : Integer;
s : string;
begin
//Fetch the attributes into a TStringList.
Result := value;
Delete(Result, 1, Length(Format('<%s ', [tag])));
Delete(Result, Pos('>', Result), Length(Result));
a.Text := Trim(Result);
//Return the input value without the Attributes.
Result := value;
Delete(Result, 1, Pos('>', Result) + 1);
Result := Format('<%s>', [tag]) + Result;
//Remove Surrounding Quotes from Value.
for i := 0 to Pred(a.Count) do
begin
s := a.Values[a.Names[i]];
if (s[1] = '"') and (s[Length(s)] = '"') then
begin
Delete(s, 1, 1);
Delete(s, Length(s), 1);
end;
a.Values[a.Names[i]] := s;
end;
end;
function FetchInnerText(tag, value: string): string;
begin
//Fetch the Text between a start and end tag.
Result := value;
Delete(Result, 1, Length(Format('<%s>', [tag])));
while not (AnsiEndsText(Format('</%s>', [tag]), Result)) do
begin
Result := Result + Trim(sl[0]);
sl.Delete(0);
end;
Delete(Result, Pos(Format('</%s>', [tag]), Result), Length(Result));
Result := Trim(Result);
end;
type
states = (xmlNone, xmlHeader, xmlNextGrid, xmlColumns, xmlColumn, xmlRows, xmlRow, xmlCells, xmlCell);
var
r, c : Integer;
i : Integer;
s : string;
state : states;
a : TStringList;
begin
sl := TStringList.Create;
NextGrid.ClearRows;
for i := 0 to Pred(NextGrid.Columns.Count) do
NextGrid.Columns[i].Header.Caption := '';
NextGrid.Update;
sl.LoadFromFile(fn);
r := 0;
c := 0;
state := xmlNone;
repeat
s := Trim(sl[0]);
sl.Delete(0);
if (CompareText(s, '<?xml version="1.0"?>') = 0) then //Process XML Version
begin
if (state <> xmlNone) then
begin
ShowMessage('Xml header not found.');
Break;
end
else
state := xmlHeader;
end
else if (CompareText(s, '<NextGrid version = "2.4.1">') = 0) then //Process NextGrid Tag
state := xmlNextGrid
else if (CompareText(s, '<Columns>') = 0) then //Process Columns Tag
begin
//sl.Add(Format(' <Column Name="%s" ColumnClass="%s">', [NextGrid.Columns[c].Name, NextGrid.Columns[c].ClassName]));
//sl.Add(' ' + EscapeValue(NextGrid.Columns[c].Header.Caption));
c := 0;
State := xmlColumns;
end
else if AnsiStartsText('<Column ', s) then //Process Column Tag
begin
state := xmlColumn;
a := TStringList.Create();
s := FetchAttributes('Column', s, a);
s := FetchInnerText('Column', s);
NextGrid.Columns[c].Header.Caption := s;
//Use StringList 'a' here to restore Column Class Dependend Values (like min/max).
//This information can also be cached to match <Cell> tags to the correct column
//so importing data after changing the order of the columns is also supported.
Inc(c);
a.Free;
state := xmlColumns;
end
else if (CompareText(s, '</Columns>') = 0) then //Finished Processing Columns Tag
begin
c := 0;
State := xmlNextGrid;
end
else if (CompareText(s, '<Rows>') = 0) then //Process Rows Tag
begin
State := xmlRows;
end
else if (AnsiStartsText(s, '<Row>')) then //Process Row Tag
begin
Inc(r);
NextGrid.AddRow();
c := 0;
State := xmlRows;
end
else if AnsiStartsText('<Cell>', s) then //Process Cell Tag
begin
State := xmlCell;
NextGrid.Cell[c, Pred(NextGrid.RowCount)].AsString := FetchInnerText('Cell', s);
Inc(c);
State := xmlCells;
end
else if (CompareText(s, '</Row>') = 0) then //Finished Processing Row Tag
begin
State := xmlRows;
end
else if (CompareText(s, '</Rows>') = 0) then //Finished Processing Rows Tag
begin
State := xmlNextGrid;
end
else if (CompareText(s, '</NextGrid>') = 0) then //Finished Processing NextGrid Tag
state := xmlNone;
until sl.Count = 0;
sl.Free;
end;
procedure NG_MoveSelectionUp(var NextGrid: TNextGrid);
var
i, j : Integer;
begin
//determine if we can move or condense any further upwards
for i := 0 to Pred(NextGrid.SelectedCount) do
if not (NextGrid.Selected[i]) then
begin
for j := i to Pred(NextGrid.RowCount) do
if (NextGrid.Selected[j]) then
NextGrid.MoveRow(j, Pred(j));
Break;
end;
end;
procedure NG_MoveSelectionDown(var NextGrid: TNextGrid);
var
i, j : Integer;
begin
//determine if we can move or condense any further downwards
for i := Pred(NextGrid.RowCount) downto (NextGrid.RowCount - NextGrid.SelectedCount) do
if not (NextGrid.Selected[i]) then
begin
for j := i downto 0 do
if (NextGrid.Selected[j]) then
NextGrid.MoveRow(j, Succ(j));
Break;
end;
end;
procedure NG_AddRowWithValues(var NextGrid: TNextGrid; const columnnames, columnvalues: array of OleVariant);
var
i : Integer;
begin
//Sample Usage:
// AddRowWithValues(NextGrid1, ['Columnname1','ColumnName2'], ['aValue',25]);
if (Length(columnnames) = Length(columnvalues)) then
begin
NextGrid.AddRow();
for i := 0 to Pred(Length(columnnames)) do
NextGrid.CellByName[columnnames[i], 'last'].AsString := columnvalues[i];
end;
end;
function NG_LookupValue(const NextGrid: TNextGrid; const lookupcolumnname, lookupvalue, valuecolumnname: OleVariant): OleVariant;
var
i : Integer;
begin
//Sample Usage:
// value:=LookupValue(NextGrid2, 'ParameterNames', 'aKey', 'ParameterValues');
Result := '';
with NextGrid do
for i := 0 to Pred(RowCount) do
if CompareText(CellByName[lookupcolumnname, i].AsString, VarToStr(lookupvalue)) = 0 then
begin
Result := CellByName[valuecolumnname, i].AsString;
Break;
end;
end;
function NG_InserNextGridTable(const NextGrid: TNextGrid): string;
var
r, c : Integer;
sl : TStringList;
begin
//Sample StyleSheet:
// <STYLE>
// TABLE {border-collapse:collapse}
// TD {border-width:1px}
// TH {background-color:silver}
// </STYLE>
sl := TStringList.Create;
sl.Add('<TABLE BORDER CELLSPACING=0 CELLPADDING=1 WIDTH="100%">');
sl.Add('<TR ALIGN="left" VALIGN="middle">');
for c := 0 to Pred(NextGrid.Columns.Count) do
sl.Add(Format(' <TH>%s</TH>', [NextGrid.Columns[c].Header.Caption]));
sl.Add('</TR>');
for r := 0 to Pred(NextGrid.RowCount) do
begin
sl.Add('<TR ALIGN="left" VALIGN="middle">');
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
if (NextGrid.Columns.Item[c] is TNxNumberColumn) then
sl.Add(Format(' <TD ALIGN="right">%s</TD>', [NextGrid.Cells[c, r]]))
else
sl.Add(Format(' <TD>%s</TD>', [NextGrid.Cells[c, r]]));
end;
sl.Add('</TR>');
end;
sl.Add('</TABLE>');
Result := sl.Text;
sl.Free;
end;
procedure NG_SaveGridData(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Section : string;
Data : TStringList;
i, j : Integer;
begin
Section := Format('%sData', [Prefix]);
with NextGrid do
begin
IniFile := TIniFile.Create(FileName);
IniFile.WriteInteger(section, 'ColumnsCount', Columns.Count);
IniFile.WriteInteger(section, 'RowsCount', RowCount);
Data := TStringList.Create;
for j := 0 to Pred(RowCount) do
begin
Data.Clear;
for i := 0 to Pred(Columns.Count) do
Data.Add(Cells[i, j]);
Data.Delimiter := ListSeparator;
IniFile.WriteString(section, Format('Row%d', [j]), Data.DelimitedText);
end;
IniFile.UpdateFile;
Data.Free;
IniFile.Free;
end;
end;
procedure NG_RestoreGridData(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Layout : TStringList;
Section : string;
Cols, Rows,
i, j : Integer;
begin
Section := Format('%sData', [Prefix]);
with NextGrid do
begin
ClearRows;
IniFile := TIniFile.Create(FileName);
Layout := TStringList.Create;
Cols := IniFile.ReadInteger(section, 'ColumnsCount', Columns.Count);
Rows := IniFile.ReadInteger(section, 'RowsCount', Columns.Count);
for j := 0 to Pred(Rows) do
begin
Layout.Delimiter := ListSeparator;
Layout.DelimitedText := IniFile.ReadString(section, Format('Row%d', [j]), '');
if (Layout.Count = Cols) then
begin
AddRow();
for i := 0 to Pred(Cols) do
Cells[i, j] := Layout[i];
end;
end;
Layout.Free;
IniFile.Free;
end;
end;
function NG_LocateGrid(const NextGrid: TNextGrid; colnames, values: array of
string): Integer;
var
i : Integer;
j : Integer;
match : Boolean;
begin
Result := -1;
if (High(colnames) <> High(Values)) then exit;
with NextGrid do
for i := 0 to Pred(RowCount) do
begin
match := True;
for j := 0 to High(colnames) do
if not SameText(CellByName[colnames[j], i].AsString, values[j]) then
begin
match := False;
break;
end;
if match then
begin
Result := i;
break;
end;
end;
end;
function NG_LookupGrid(const NextGrid: TNextGrid; colnames: array of string;
values: array of variant; return: string): string;
var
i : Integer;
j : Integer;
match : Boolean;
begin
Result := '';
if (High(colnames) <> High(Values)) then exit;
with NextGrid do
for i := 0 to Pred(RowCount) do
begin
match := True;
for j := 0 to High(colnames) do
if not SameText(CellByName[colnames[j], i].AsString, VarToStr(values[j])) then
begin
match := False;
break;
end;
if match then
begin
Result := CellByName[return, i].AsString;
break;
end;
end;
end;
end.
{----Purpose : NextGrid utilities }
{ By : Ir. G.W. van der Vegt }
{ For : Myself. }
{ Depends : NextGrid }
{-----------------------------------------------------------}
{ ddmmyyyy comment }
{ -------- ------------------------------------------------ }
{ ddmmyyyy-Initial version }
{ 26052005-Translated to NextGrid. }
{ -Added NG_ToCsvString function. }
{-----------------------------------------------------------}
{ notes: }
{ 1. }
{-----------------------------------------------------------}
{ todo: }
{ 1. }
{-----------------------------------------------------------}
unit NextGridUtils;
interface
uses
NxGrid;
procedure NG_SaveGridLayout(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_RestoreGridLayout(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_SaveGridData(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_RestoreGridData(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
procedure NG_ExportToCsv(const NextGrid: TNextGrid; const fn: string; const header: Boolean = True; const selected: Boolean = False);
function NG_ToCsvString(const NextGrid: TNextGrid; const header: Boolean = True; const selected: Boolean = False): string;
procedure NG_ExportToXml(const NextGrid: TNextGrid; const fn: string);
procedure NG_ImportFromXml(var NextGrid: TNextGrid; const fn: string);
procedure NG_MoveSelectionUp(var NextGrid: TNextGrid);
procedure NG_MoveSelectionDown(var NextGrid: TNextGrid);
procedure NG_AddRowWithValues(var NextGrid: TNextGrid; const columnnames, columnvalues: array of OleVariant);
function NG_LookupValue(const NextGrid: TNextGrid; const lookupcolumnname, lookupvalue, valuecolumnname: OleVariant): OleVariant;
function NG_InserNextGridTable(const NextGrid: TNextGrid): string;
function NG_LocateGrid(const NextGrid: TNextGrid; colnames, values: array of
string): Integer;
function NG_LookupGrid(const NextGrid: TNextGrid; colnames: array of string;
values: array of variant; return: string): string;
implementation
uses
NxCustomGridControl,
NxColumnClasses,
NxColumns,
Classes,
Dialogs,
IniFiles,
StrUtils,
SysUtils,
Variants;
procedure NG_SaveGridLayout(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Section : string;
Layout : TStringList;
i : Integer;
begin
Section := Format('%sLayout', [Prefix]);
with NextGrid do
begin
IniFile := TIniFile.Create(FileName);
IniFile.WriteInteger(section, 'ColumnsCount', Columns.Count);
Layout := TStringList.Create;
for i := 0 to Pred(Columns.Count) do
begin
Layout.Clear;
Layout.Add(IntToStr(Ord(Columns[i].SortKind)));
Layout.Add(IntToStr(Ord(Columns[i].Visible)));
Layout.Add(IntToStr(Ord(Columns[i].Sorted)));
Layout.Add(IntToStr(Ord(Columns[i].Position)));
Layout.Add(IntToStr(Ord(Columns[i].Width)));
Layout.Delimiter := ListSeparator;
IniFile.WriteString(section, Format('Column%d', [i]), Layout.DelimitedText);
end;
IniFile.UpdateFile;
Layout.Free;
IniFile.Free;
end;
end;
procedure NG_RestoreGridLayout(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Layout : TStringList;
Section : string;
Count,
i : Integer;
begin
Section := Format('%sLayout', [Prefix]);
with NextGrid do
begin
IniFile := TIniFile.Create(FileName);
Layout := TStringList.Create;
Count := IniFile.ReadInteger(section, 'ColumnsCount', Columns.Count);
for i := 0 to Pred(Count) do
begin
Layout.Delimiter := ListSeparator;
Layout.DelimitedText := IniFile.ReadString(section, Format('Column%d', [i]), '');
if (Layout.Count = 5) then
begin
Columns[i].SortKind := TSortKind(StrToInt(Layout[0]));
Columns[i].Visible := Boolean(StrToInt(Layout[1]));
Columns[i].Sorted := Boolean(StrToInt(Layout[2]));
Columns[i].Position := StrToInt(Layout[3]);
Columns[i].Width := StrToInt(Layout[4]);
end;
end;
Layout.Free;
IniFile.Free;
end;
end;
procedure NG_ExportToCsv(const NextGrid: TNextGrid; const fn: string; const header: Boolean = True; const selected: Boolean = False);
var
sl : TStringList;
begin
sl := TStringList.Create;
sl.Text := NG_ToCsvString(NextGrid, header, selected);
sl.SaveToFile(fn);
sl.Free;
end;
function NG_ToCsvString(const NextGrid: TNextGrid; const header: Boolean = True; const selected: Boolean = False): string;
{
normalcol;"colwithlistseparator;";"colwithquote"""
1;2;5
4;3;6
}
var
r, c : Integer;
sl : TStringList;
s : string;
function EscapeSeparator(const value: string): string;
begin
if (Pos('"', value) > 0) then
Result := StringReplace(value, '"', '""', [rfReplaceAll])
else
Result := value;
if (Pos(ListSeparator, Result) > 0) or (Pos('""', Result) > 0) then
Result := '"' + Result + '"'
end;
begin
sl := TStringList.Create;
if header then
begin
s := '';
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
if c <> 0 then
s := s + ListSeparator + EscapeSeparator(NextGrid.Columns[c].Header.Caption)
else
s := EscapeSeparator(NextGrid.Columns[c].Header.Caption);
end;
sl.Add(s);
end;
for r := 0 to Pred(NextGrid.RowCount) do
if selected and NextGrid.Selected[r] then
begin
s := '';
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
if c <> 0 then
s := s + ListSeparator + EscapeSeparator(NextGrid.Cell[c, r].AsString)
else
s := EscapeSeparator(NextGrid.Cell[c, r].AsString);
end;
sl.Add(s);
end;
Result := sl.Text;
sl.Free;
end;
procedure NG_ExportToXml(const NextGrid: TNextGrid; const fn: string);
var
r, c : Integer;
sl : TStringList;
function EscapeValue(const value: string): string;
begin
//Not implemented yet.
//Change all characters outside the letters, numbers and crlf to
//< format where 3C is the hex value of the Characters Ord.
Result := value;
end;
begin
sl := TStringList.Create;
sl.Add('<?xml version="1.0"?>');
sl.Add(Format('<NextGrid version = "%s">', ['2.4.1'])); //Should be stVersion!
sl.Add(' <Columns>');
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
//Use Attributes to Export Column Dependend settings like min/max values.
sl.Add(Format(' <Column Name="%s" ColumnClass="%s">', [NextGrid.Columns[c].Name, NextGrid.Columns[c].ClassName]));
sl.Add(' ' + EscapeValue(NextGrid.Columns[c].Header.Caption));
sl.Add(' </Column>');
end;
sl.Add(' </Columns>');
sl.Add(' <Rows>');
for r := 0 to Pred(NextGrid.RowCount) do
begin
sl.Add(' <Row>');
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
sl.Add(' <Cell>');
{if not (NextGrid.Columns[c].ClassNameIs('TGraphicColumn') or
NextGrid.Columns[c].ClassNameIs('TImageColumn')) then}
sl.Add(' ' + EscapeValue(NextGrid.Cell[c, r].AsString));
sl.Add(' </Cell>');
end;
sl.Add(' </Row>');
end;
sl.Add(' </Rows>');
sl.Add('</NextGrid>');
sl.SaveToFile(fn);
sl.Free;
end;
procedure NG_ImportFromXml(var NextGrid: TNextGrid; const fn: string);
var
sl : TStringList;
function FetchAttributes(tag, value: string; var a: TStringList): string;
var
i : Integer;
s : string;
begin
//Fetch the attributes into a TStringList.
Result := value;
Delete(Result, 1, Length(Format('<%s ', [tag])));
Delete(Result, Pos('>', Result), Length(Result));
a.Text := Trim(Result);
//Return the input value without the Attributes.
Result := value;
Delete(Result, 1, Pos('>', Result) + 1);
Result := Format('<%s>', [tag]) + Result;
//Remove Surrounding Quotes from Value.
for i := 0 to Pred(a.Count) do
begin
s := a.Values[a.Names[i]];
if (s[1] = '"') and (s[Length(s)] = '"') then
begin
Delete(s, 1, 1);
Delete(s, Length(s), 1);
end;
a.Values[a.Names[i]] := s;
end;
end;
function FetchInnerText(tag, value: string): string;
begin
//Fetch the Text between a start and end tag.
Result := value;
Delete(Result, 1, Length(Format('<%s>', [tag])));
while not (AnsiEndsText(Format('</%s>', [tag]), Result)) do
begin
Result := Result + Trim(sl[0]);
sl.Delete(0);
end;
Delete(Result, Pos(Format('</%s>', [tag]), Result), Length(Result));
Result := Trim(Result);
end;
type
states = (xmlNone, xmlHeader, xmlNextGrid, xmlColumns, xmlColumn, xmlRows, xmlRow, xmlCells, xmlCell);
var
r, c : Integer;
i : Integer;
s : string;
state : states;
a : TStringList;
begin
sl := TStringList.Create;
NextGrid.ClearRows;
for i := 0 to Pred(NextGrid.Columns.Count) do
NextGrid.Columns[i].Header.Caption := '';
NextGrid.Update;
sl.LoadFromFile(fn);
r := 0;
c := 0;
state := xmlNone;
repeat
s := Trim(sl[0]);
sl.Delete(0);
if (CompareText(s, '<?xml version="1.0"?>') = 0) then //Process XML Version
begin
if (state <> xmlNone) then
begin
ShowMessage('Xml header not found.');
Break;
end
else
state := xmlHeader;
end
else if (CompareText(s, '<NextGrid version = "2.4.1">') = 0) then //Process NextGrid Tag
state := xmlNextGrid
else if (CompareText(s, '<Columns>') = 0) then //Process Columns Tag
begin
//sl.Add(Format(' <Column Name="%s" ColumnClass="%s">', [NextGrid.Columns[c].Name, NextGrid.Columns[c].ClassName]));
//sl.Add(' ' + EscapeValue(NextGrid.Columns[c].Header.Caption));
c := 0;
State := xmlColumns;
end
else if AnsiStartsText('<Column ', s) then //Process Column Tag
begin
state := xmlColumn;
a := TStringList.Create();
s := FetchAttributes('Column', s, a);
s := FetchInnerText('Column', s);
NextGrid.Columns[c].Header.Caption := s;
//Use StringList 'a' here to restore Column Class Dependend Values (like min/max).
//This information can also be cached to match <Cell> tags to the correct column
//so importing data after changing the order of the columns is also supported.
Inc(c);
a.Free;
state := xmlColumns;
end
else if (CompareText(s, '</Columns>') = 0) then //Finished Processing Columns Tag
begin
c := 0;
State := xmlNextGrid;
end
else if (CompareText(s, '<Rows>') = 0) then //Process Rows Tag
begin
State := xmlRows;
end
else if (AnsiStartsText(s, '<Row>')) then //Process Row Tag
begin
Inc(r);
NextGrid.AddRow();
c := 0;
State := xmlRows;
end
else if AnsiStartsText('<Cell>', s) then //Process Cell Tag
begin
State := xmlCell;
NextGrid.Cell[c, Pred(NextGrid.RowCount)].AsString := FetchInnerText('Cell', s);
Inc(c);
State := xmlCells;
end
else if (CompareText(s, '</Row>') = 0) then //Finished Processing Row Tag
begin
State := xmlRows;
end
else if (CompareText(s, '</Rows>') = 0) then //Finished Processing Rows Tag
begin
State := xmlNextGrid;
end
else if (CompareText(s, '</NextGrid>') = 0) then //Finished Processing NextGrid Tag
state := xmlNone;
until sl.Count = 0;
sl.Free;
end;
procedure NG_MoveSelectionUp(var NextGrid: TNextGrid);
var
i, j : Integer;
begin
//determine if we can move or condense any further upwards
for i := 0 to Pred(NextGrid.SelectedCount) do
if not (NextGrid.Selected[i]) then
begin
for j := i to Pred(NextGrid.RowCount) do
if (NextGrid.Selected[j]) then
NextGrid.MoveRow(j, Pred(j));
Break;
end;
end;
procedure NG_MoveSelectionDown(var NextGrid: TNextGrid);
var
i, j : Integer;
begin
//determine if we can move or condense any further downwards
for i := Pred(NextGrid.RowCount) downto (NextGrid.RowCount - NextGrid.SelectedCount) do
if not (NextGrid.Selected[i]) then
begin
for j := i downto 0 do
if (NextGrid.Selected[j]) then
NextGrid.MoveRow(j, Succ(j));
Break;
end;
end;
procedure NG_AddRowWithValues(var NextGrid: TNextGrid; const columnnames, columnvalues: array of OleVariant);
var
i : Integer;
begin
//Sample Usage:
// AddRowWithValues(NextGrid1, ['Columnname1','ColumnName2'], ['aValue',25]);
if (Length(columnnames) = Length(columnvalues)) then
begin
NextGrid.AddRow();
for i := 0 to Pred(Length(columnnames)) do
NextGrid.CellByName[columnnames[i], 'last'].AsString := columnvalues[i];
end;
end;
function NG_LookupValue(const NextGrid: TNextGrid; const lookupcolumnname, lookupvalue, valuecolumnname: OleVariant): OleVariant;
var
i : Integer;
begin
//Sample Usage:
// value:=LookupValue(NextGrid2, 'ParameterNames', 'aKey', 'ParameterValues');
Result := '';
with NextGrid do
for i := 0 to Pred(RowCount) do
if CompareText(CellByName[lookupcolumnname, i].AsString, VarToStr(lookupvalue)) = 0 then
begin
Result := CellByName[valuecolumnname, i].AsString;
Break;
end;
end;
function NG_InserNextGridTable(const NextGrid: TNextGrid): string;
var
r, c : Integer;
sl : TStringList;
begin
//Sample StyleSheet:
// <STYLE>
// TABLE {border-collapse:collapse}
// TD {border-width:1px}
// TH {background-color:silver}
// </STYLE>
sl := TStringList.Create;
sl.Add('<TABLE BORDER CELLSPACING=0 CELLPADDING=1 WIDTH="100%">');
sl.Add('<TR ALIGN="left" VALIGN="middle">');
for c := 0 to Pred(NextGrid.Columns.Count) do
sl.Add(Format(' <TH>%s</TH>', [NextGrid.Columns[c].Header.Caption]));
sl.Add('</TR>');
for r := 0 to Pred(NextGrid.RowCount) do
begin
sl.Add('<TR ALIGN="left" VALIGN="middle">');
for c := 0 to Pred(NextGrid.Columns.Count) do
begin
if (NextGrid.Columns.Item[c] is TNxNumberColumn) then
sl.Add(Format(' <TD ALIGN="right">%s</TD>', [NextGrid.Cells[c, r]]))
else
sl.Add(Format(' <TD>%s</TD>', [NextGrid.Cells[c, r]]));
end;
sl.Add('</TR>');
end;
sl.Add('</TABLE>');
Result := sl.Text;
sl.Free;
end;
procedure NG_SaveGridData(const NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Section : string;
Data : TStringList;
i, j : Integer;
begin
Section := Format('%sData', [Prefix]);
with NextGrid do
begin
IniFile := TIniFile.Create(FileName);
IniFile.WriteInteger(section, 'ColumnsCount', Columns.Count);
IniFile.WriteInteger(section, 'RowsCount', RowCount);
Data := TStringList.Create;
for j := 0 to Pred(RowCount) do
begin
Data.Clear;
for i := 0 to Pred(Columns.Count) do
Data.Add(Cells[i, j]);
Data.Delimiter := ListSeparator;
IniFile.WriteString(section, Format('Row%d', [j]), Data.DelimitedText);
end;
IniFile.UpdateFile;
Data.Free;
IniFile.Free;
end;
end;
procedure NG_RestoreGridData(var NextGrid: TNextGrid; const FileName: string; const Prefix: string = '');
var
IniFile : TIniFile;
Layout : TStringList;
Section : string;
Cols, Rows,
i, j : Integer;
begin
Section := Format('%sData', [Prefix]);
with NextGrid do
begin
ClearRows;
IniFile := TIniFile.Create(FileName);
Layout := TStringList.Create;
Cols := IniFile.ReadInteger(section, 'ColumnsCount', Columns.Count);
Rows := IniFile.ReadInteger(section, 'RowsCount', Columns.Count);
for j := 0 to Pred(Rows) do
begin
Layout.Delimiter := ListSeparator;
Layout.DelimitedText := IniFile.ReadString(section, Format('Row%d', [j]), '');
if (Layout.Count = Cols) then
begin
AddRow();
for i := 0 to Pred(Cols) do
Cells[i, j] := Layout[i];
end;
end;
Layout.Free;
IniFile.Free;
end;
end;
function NG_LocateGrid(const NextGrid: TNextGrid; colnames, values: array of
string): Integer;
var
i : Integer;
j : Integer;
match : Boolean;
begin
Result := -1;
if (High(colnames) <> High(Values)) then exit;
with NextGrid do
for i := 0 to Pred(RowCount) do
begin
match := True;
for j := 0 to High(colnames) do
if not SameText(CellByName[colnames[j], i].AsString, values[j]) then
begin
match := False;
break;
end;
if match then
begin
Result := i;
break;
end;
end;
end;
function NG_LookupGrid(const NextGrid: TNextGrid; colnames: array of string;
values: array of variant; return: string): string;
var
i : Integer;
j : Integer;
match : Boolean;
begin
Result := '';
if (High(colnames) <> High(Values)) then exit;
with NextGrid do
for i := 0 to Pred(RowCount) do
begin
match := True;
for j := 0 to High(colnames) do
if not SameText(CellByName[colnames[j], i].AsString, VarToStr(values[j])) then
begin
match := False;
break;
end;
if match then
begin
Result := CellByName[return, i].AsString;
break;
end;
end;
end;
end.