My understanding is that generics help when dealing with a variety of simple types in a generic way, but are not so readily applied to complex or structured types.
Here is one way to encapsulate your string data. You would probably want to add better error-checking, and ways to locate, sort and delete on individual data such as a particular operating system; but I don't know what your requirements are for that.
unit main3StringList;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Grids, strutils;
type
{ T3stringList }
T3stringList = class(TStringList)
private
FInnerDelim: AnsiChar;
FInnerDelimiter: AnsiChar;
function GetFileName(index: integer): AnsiString;
function GetOS(index: integer): AnsiString;
function GetSourceURL(index: integer): AnsiString;
function Parse3String(const s: string; var URL, OS, FName: AnsiString): boolean;
public
constructor Create(anInnerDelimiter: AnsiChar);
procedure Add3String(const aSource, anOs, aFileName: ansistring);
property InnerDelimiter: AnsiChar read FInnerDelimiter;
property SourceURLs[index: integer]: AnsiString read GetSourceURL;
property OSs[index: integer]: AnsiString read GetOS;
property FileNames[index: integer]: AnsiString read GetFileName;
end;
{ TForm1 }
TForm1 = class(TForm)
grid: TStringGrid;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
threeSL: T3stringList;
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
threeSL:=T3stringList.Create(#11);
threeSL.Add3String('www.freepascal.org','linux','/home/etc/some');
threeSL.Add3String('www.blaisepascal.eu','Windows','C:\autoexec.bat');
threeSL.Add3String('www.embarcadero.com','Mac OS X','file name3');
grid.ColCount:=3;
grid.RowCount:=threeSL.Count;
for i:=0 to threeSL.Count-1 do begin
grid.Cells[0,i]:=threeSL.SourceURLs[i];
grid.Cells[1,i]:=threeSL.OSs[i];
grid.Cells[2,i]:=threeSL.FileNames[i];
end;
grid.AutoSizeColumns;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
threeSL.Free;
end;
{$R *.lfm}
{ T3stringList }
function T3stringList.GetFileName(index: integer): AnsiString;
var
url, os: AnsiString;
begin
if not ( (index>=0) and (index<Count) and
Parse3String(Self[index],url, os, Result) )
then Result:='';
end;
function T3stringList.GetOS(index: integer): AnsiString;
var
url, fname: AnsiString;
begin
if not ( (index>=0) and (index<Count) and
Parse3String(Self[index],url, Result, fname) )
then Result:='';
end;
function T3stringList.GetSourceURL(index: integer): AnsiString;
var
os, fname: AnsiString;
begin
if not ( (index>=0) and (index<Count) and
Parse3String(Self[index], Result, os, fname) )
then Result:='';
end;
function T3stringList.Parse3String(const s: string; var URL, OS, FName: AnsiString): boolean;
function DelimCount: integer;
var
c: AnsiChar;
begin
Result:=0;
for c in s do
if (c = FInnerDelimiter) then
Inc(Result);
end;
var
p1, p2: integer;
begin
if (DelimCount <> 2) then
Exit(False);
p1:=Pos(FInnerDelimiter, s);
url:=Copy(s, 1, Pred(p1));
p2:=PosEx(FInnerDelimiter, s, Succ(p1));
OS:=Copy(s, Succ(p1), Pred(p2-p1));
FName:=Copy(s, Succ(p2), maxint);
Result:=True;
end;
constructor T3stringList.Create(anInnerDelimiter: AnsiChar);
begin
inherited Create;
FInnerDelimiter:=anInnerDelimiter;
end;
procedure T3stringList.Add3String(const aSource, anOs, aFileName: ansistring);
begin
Add(Format('%s%s%s%s%s',[aSource,FInnerDelimiter,anOs,FInnerDelimiter,aFileName]));
end;
end.