home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 December / Chip_2001-12_cd1.bin / zkuste / delphi / kolekce / d56 / DM2KVCL.ZIP / DATA.PAS < prev    next >
Pascal/Delphi Source File  |  2000-12-31  |  21KB  |  569 lines

  1. {****************************************************************************}
  2. {                            Data Master 2000                                }
  3. {****************************************************************************}
  4. unit Data;
  5. {$I+,B-,X+}
  6. interface
  7.  
  8. uses
  9.   Windows, Messages, Classes, SysUtils, Controls, Forms, Dialogs, Common;
  10.  
  11. type
  12.  
  13. {--- Data elements ---}
  14.  
  15.   TData=class                               {abstract class for data elements}
  16.   protected
  17.     function GetData: string; virtual; abstract;           {for Data property}
  18.     procedure SetData(S: string); virtual; abstract;
  19.     procedure FreeData; virtual;            {disposes off occupied heap space}
  20.     procedure LoadData(var F: text); virtual;              {text file support}
  21.     procedure SaveData(var F: text); virtual;
  22.     procedure ReadData(S: TStream); virtual; abstract;        {stream support}
  23.     procedure WriteData(S: TStream); virtual; abstract;
  24.   public
  25.     property Data: string read GetData write SetData;   {string image of data}
  26.     destructor Destroy; override;
  27.     procedure Copy(D: TData); virtual;    // copies data from D w/o conversion
  28.   end;
  29.  
  30.   TStringData=class(TData)           {represents dynamically allocated string}
  31.   private                            {this class is similar to old DM object!}
  32.     FData: PString;
  33.   protected
  34.     function GetData: string; override;
  35.     procedure SetData(S: string); override;
  36.     procedure FreeData; override;
  37.     procedure ReadData(S: TStream);  override;
  38.     procedure WriteData(S: TStream); override;
  39.   end;
  40.  
  41.   TFunction=class(TData)                       {represents Y(X) (2D) function}
  42.   protected
  43.     function GetData: string; override;
  44.     procedure SetData(S: string); override;
  45.     procedure LoadData(var F: text); override;        {use direct file access}
  46.     procedure SaveData(var F: text); override;
  47.     procedure ReadData(S: TStream);  override;
  48.     procedure WriteData(S: TStream); override;
  49.   public
  50.     X,Y:TReal;
  51.   end;
  52.  
  53.   ERealDataError=class(Exception);      {raised when data access error occurs}
  54.  
  55.   TRealData=class(TData)             {similar to according DM/DMW data object}
  56.   private
  57.     FNumCol: integer;
  58.     FData: PRealArray;
  59.   protected
  60.     function GetData: string; override;
  61.     procedure SetData(S: string); override;
  62.     procedure FreeData; override;
  63.     procedure ReadData(S: TStream);  override;
  64.     procedure WriteData(S: TStream); override;
  65.   public
  66.     Format: PFormatArray;                    {points to window's format array}
  67.     class function GetClipboardFormat: word;
  68.     function GetItemText(N: integer): string;     {returns text of n-th value}
  69.     function GetRData(var R: TRealArray): integer;  {returns number of values}
  70.     procedure SetRData(N: integer; R: TRealArray);                 {set array}
  71.     function GetItem(N: integer): TReal;                  {returns n-th value}
  72.     procedure SetItem(N: integer; R: TReal);                       {set --#--}
  73.     procedure DelItem(N: integer);                              {delete --#--}
  74.     procedure InsItem(R: TReal);                                   {add value}
  75.     procedure Copy(D: TData); override; // copy data w/o truncation and format
  76.     property Size: integer read FNumCol;
  77.     property RData[N:integer]: TReal read GetItem write SetItem; default;
  78.   end;
  79.  
  80.   T3DFunction=class(TRealData) {introduce 3D function without additional code}
  81.   public
  82.     property X: TReal index 1 read GetItem write SetItem;
  83.     property Y: TReal index 2 read GetItem write SetItem;
  84.     property Z: TReal index 3 read GetItem write SetItem;
  85.   end;
  86.  
  87. {--- Data container ---}
  88.  
  89.   TDataType=(dtCustom, dtStringData, dtFunction, dtRealData);
  90.   TCompareResult=(crGreater, crLess, crEqual);
  91.   TCompareEvent=function(Sender: TObject;
  92.                 I1,I2: TData): TCompareResult of object;
  93.   TInitItemEvent=function(Sender: TObject): TData of object;
  94.   TProgressEvent=procedure(Sender: TObject; P: integer) of object;
  95.   TDataClass=class of TData;
  96.  
  97.   TContainer=class(TComponent)                     {container component class}
  98.   private
  99.     FFileName: string;         
  100.     FDataClass: TDataClass;
  101.     FUpdateCaption: boolean;
  102.     FAutoLoad: boolean;
  103.     FList: TList;
  104.     FInitItem: TInitItemEvent;
  105.     FProgress: TProgressEvent;
  106.     FModified: boolean;
  107.     FChanged: TNotifyEvent;                     {used for "changed" indicator}
  108.     FCompare: TCompareEvent;
  109.     DataCache: TReal;                     {buffers for Calibrate: value cache}
  110.     RowCache: TRealArray;                                    {table row cache}
  111.     procedure SetDataType(T: TDataType);                 {simulate data field}
  112.     function GetDataType: TDataType;
  113.     procedure SetFileName(FN: string);
  114.     procedure SetModified(M: boolean);
  115.   protected
  116.     procedure DefineProperties(Filer: TFiler); override;      {for store data}
  117.   public
  118.     property Items: TList read FList;
  119.     property Modified: boolean read FModified write SetModified;
  120.     property DataClass: TDataClass read FDataClass write FDataClass;
  121.     procedure ShowProgress(P: integer); virtual;  {these 2 may be overridden!}
  122.     function InitItem: TData; virtual;
  123.     constructor Create(AOwner: TComponent); override;
  124.     destructor Destroy; override;
  125.     procedure Clear;
  126.     procedure LoadFromFile;                                {text file support}
  127.     procedure SaveToFile(Backup: boolean); {when true, save will cause backup}
  128.     procedure LoadFromStream(S: TStream);                     {stream support}
  129.     procedure SaveToStream(S: TStream);
  130.     procedure Sort(BegLine,EndLine: integer; Descend: boolean);
  131.     procedure Assign(Source: TPersistent); override;    {container or strings}
  132.     function Calibrate(R:TReal; Index,Key: integer): TReal;{table calibration}
  133.   published
  134.     property FileName: string read FFileName write SetFileName;
  135.     property DataType: TDataType read GetDataType write SetDataType;
  136.     property UpdateCaption: boolean read FUpdateCaption write FUpdateCaption;
  137.     property AutoLoad: boolean read FAutoLoad write FAutoLoad;
  138.     property OnInitItem: TInitItemEvent read FInitItem write FInitItem;
  139.     property OnProgress: TProgressEvent read FProgress write FProgress;
  140.     property OnChanged: TNotifyEvent read FChanged write FChanged;
  141.     property OnCompare: TCompareEvent read FCompare write FCompare;
  142.   end;
  143.  
  144. procedure Register;
  145.  
  146. resourcestring
  147.   errDelItem='Cannot delete item!';
  148.   errSetItem='Cannot set item!';
  149.   errGetItem='Cannot get item!';
  150.   errInsItem='Cannot insert item!';
  151.   errInitItem='Cannot initialize item!';
  152.   msgSetCustom='You need to define %s.OnInitItem or DataClass!';
  153.   errSort='Unable to sort lines!';
  154.  
  155. implementation
  156.  
  157. {--- TData ---}
  158.  
  159. procedure TData.LoadData(var F: text);
  160. var S: string;
  161. begin readln(F, S); Data:=S; end;
  162.  
  163. procedure TData.SaveData(var F: text);
  164. begin writeln(F, Data); end;
  165.  
  166. destructor TData.Destroy;      {in addition, disposes off occupied heap space}
  167. begin FreeData; inherited Destroy; end;
  168.  
  169. procedure TData.FreeData;
  170. begin end;       {does nothing, but not abstract - called in all descendants!}
  171.  
  172. procedure TData.Copy(D: TData);
  173. begin Data:=D.Data end;                    // by default, simply copies string
  174.  
  175. {--- TStringData ---}
  176.  
  177. procedure TStringData.FreeData;
  178. begin if assigned(FData) then DisposeStr(FData); FData:=nil; end;
  179.  
  180. function TStringData.GetData: string;
  181. begin if assigned(FData) then result:=FData^ else result:=''; end;
  182.  
  183. procedure TStringData.SetData(S: string);
  184. begin FreeData; if S<>'' then FData:=NewStr(S); end;
  185.  
  186. procedure TStringData.ReadData(S: TStream);
  187. var D: shortstring;
  188. begin S.ReadBuffer(D[0],1); S.ReadBuffer(D[1],byte(D[0])); Data:=D; end;
  189.  
  190. procedure TStringData.WriteData(S: TStream);
  191. var D: shortstring;
  192. begin D:=Data; S.WriteBuffer(D[0], length(D)+1); end;
  193.  
  194. {--- TFunction ---}
  195.  
  196. {constructor TFunction.Create(xx,yy: TReal);
  197. begin inherited Create; X:=xx; Y:=yy; end;}
  198.  
  199. function TFunction.GetData: string;
  200. begin Result:=FloatToStr(X)+' '+FloatToStr(y); end;
  201.  
  202. procedure TFunction.SetData(S: string);
  203. var R: TRealArray; N: integer;
  204. begin N:=Str2Real(S, R); if N>0 then X:=R[1]; if N>1 then Y:=R[2]; end;
  205.  
  206. procedure TFunction.LoadData(var F: text);
  207. begin readln(F, X, Y); end;
  208.  
  209. procedure TFunction.SaveData(var F: text);
  210. begin writeln(F, X, Y); end;
  211.  
  212. procedure TFunction.ReadData(S: TStream);
  213. begin S.ReadBuffer(X, Sizeof(X)); S.ReadBuffer(Y, Sizeof(Y)); end;
  214.  
  215. procedure TFunction.WriteData(S: TStream);
  216. begin S.WriteBuffer(X, Sizeof(X)); S.WriteBuffer(Y, Sizeof(Y)); end;
  217.  
  218. {--- TRealData ---}
  219.  
  220. const RealDataFormat: word=0;
  221.  
  222. function TRealData.GetData: string;
  223. var I: integer;
  224. begin
  225.   result:=''; for I:=1 to FNumCol do result:=result+GetItemText(I)+' ';
  226. end;
  227.  
  228. procedure TRealData.SetData(S: string);
  229. var R: TRealArray; N: integer;
  230. begin  N:=Str2Real(S, R); SetRData(N,R); end;
  231.  
  232. procedure TRealData.FreeData;
  233. begin
  234.   if assigned(FData) then FreeMem(FData, FNumCol*SizeOf(TReal));
  235.   FNumCol:=0; FData:=nil;
  236. end;
  237.  
  238. function TRealData.GetItemText(N: integer): string;
  239. var W, D: integer; F: TFloatFormat;
  240. begin
  241.   if N>FNumCol then begin result:=''; Exit; end;               {no such item!}
  242.   if assigned(Format) then with Format^[N] do                     {get format}
  243.   begin W:=Width; D:=Decimals; F:=FType; end
  244.   else begin W:=15; D:=7; F:=ffGeneral; end;
  245.   result:=FloatToStrF(GetItem(N), F, W, D);                 {make item's text}
  246. end;
  247.  
  248. function TRealData.GetRData(var R: TRealArray): integer;
  249. var I: integer;
  250. begin for I:=1 to FNumCol do R[I]:=FData^[I]; GetRData:=FNumCol; end;
  251.  
  252. procedure TRealData.SetRData(N: integer; R: TRealArray);
  253. var I: integer;
  254. begin
  255.   FreeData; if N<1 then Exit; FNumCol:=N;
  256.   GetMem(FData, N*SizeOf(TReal)); for I:=1 to N do FData^[I]:=R[I];
  257. end;
  258.  
  259. function TRealData.GetItem(N: integer): TReal;
  260. begin
  261.   if (N<1) or (N>FNumCol) then raise ERealDataError.Create(errGetItem)
  262.   else result:=FData^[N];
  263. end;
  264.  
  265. procedure TRealData.SetItem(N: integer; R: TReal);
  266. begin
  267.   if (N<1) or (N>FNumCol) then raise ERealDataError.Create(errSetItem)
  268.   else FData^[N]:=R;
  269. end;
  270.  
  271. procedure TRealData.DelItem(N: integer);
  272. var I,J,K: integer; R: TRealArray;
  273. begin
  274.   if (N<1) or (N>FNumCol) then
  275.   begin raise ERealDataError.Create(errDelItem); Exit; end;
  276.   K:=FNumCol; for I:=1 to K do R[I]:=FData^[I]; FreeData;          {save data}
  277.   GetMem(FData, (K-1)*SizeOf(TReal)); FNumCol:=K-1;               {del column}
  278.   J:=1; for I:=1 to K do if I<>N then begin FData^[J]:=R[I]; Inc(J); end;
  279. end;
  280.  
  281. procedure TRealData.InsItem(R: TReal);
  282. var I,N: integer; Rr: TRealArray;
  283. begin
  284.   if FNumCol=MaxCols then raise ERealDataError.Create(errInsItem)
  285.   else begin
  286.     N:=FNumCol; for I:=1 to N do Rr[I]:=FData^[I]; FreeData;       {save data}
  287.     GetMem(FData, (N+1)*SizeOf(TReal)); FNumCol:=N+1;             {add column}
  288.     for I:=1 to N do FData^[I]:=Rr[I]; FData^[N+1]:=R;            {ins to end}
  289.   end;
  290. end;
  291.  
  292. procedure TRealData.ReadData(S: TStream);             {2.0 change: N=BYTE!!!!}
  293. var I,N: byte; R: TRealArray;
  294. begin
  295.   N:=FNumCol; S.ReadBuffer(N, SizeOf(N));
  296.   for I:=1 to N do S.ReadBuffer(R[I], SizeOf(TReal));
  297.   SetRData(N,R);
  298. end;
  299.  
  300. procedure TRealData.WriteData(S: TStream);
  301. var I,N: byte;
  302. begin
  303.   N:=FNumCol; S.WriteBuffer(N, SizeOf(N));
  304.   for I:=1 to N do S.WriteBuffer(FData^[I], SizeOf(TReal));
  305. end;
  306.  
  307. procedure TRealData.Copy(D: TData);
  308. var R: TRealArray; N: byte;
  309. begin
  310.   if D is TRealData then
  311.   begin
  312.     N:=(D as TRealData).GetRData(R); Format:=(D as TRealData).Format;
  313.     SetRData(N,R);
  314.   end else inherited;
  315. end;
  316.  
  317. class function TRealData.GetClipboardFormat: word;
  318. begin
  319.   if RealDataFormat=0 then Result:=RegisterClipboardFormat('TRealData Array')
  320.   else Result:=RealDataFormat;
  321. end;
  322.  
  323. {--- TContainer ---}
  324.  
  325. constructor TContainer.Create(AOwner: TComponent);
  326. begin
  327.   inherited Create(AOwner);
  328.   FFileName:='NONAME';
  329.   FUpdateCaption:=false;
  330.   FAutoLoad:=false;
  331.   FDataClass:=TStringData;
  332.   FList:=TList.Create;
  333.   FModified:=false;
  334. end;
  335.  
  336. destructor TContainer.Destroy;                    {clears & disposes off list}
  337. begin Clear; if Assigned(FList) then Flist.Free; inherited Destroy; end;
  338.  
  339. function TContainer.InitItem: TData;       {inits data element when load file}
  340. begin                                                         {NOTE: virtual!}
  341.   if Assigned(FInitItem) then Result:=FInitItem(Self)
  342.   else if Assigned(FDataClass) then Result:=FDataClass.Create else
  343.   begin
  344.     MessageDlg(errInitItem, mtError, [mbCancel], 0); Result:=nil;
  345.   end;
  346. end;
  347.  
  348. {NOTE! CUSTOM TYPE MEANS THAT YOU NEED EITHER DEFINE ONINITITEM OR SET
  349. DATACLASS PROPERTY(AT RUNTIME)! ELSE INITITEM WILL FAIL.}
  350.  
  351. procedure TContainer.ShowProgress(P: integer);                {NOTE: virtual!}
  352. begin if Assigned(FProgress) then FProgress(Self, P); end;
  353.  
  354. procedure TContainer.SetDataType(T: TDataType);
  355. begin
  356.   case T of
  357.     dtCustom: begin
  358.                 if csDesigning in ComponentState then          {warn designer}
  359.                 MessageDlg(Format(msgSetCustom,[Name]), mtWarning, [mbOk], 0);
  360.                 FDataClass:=nil;
  361.               end;
  362.     dtStringData: FDataClass:=TStringData;                    {set class type}
  363.     dtFunction: FDataClass:=TFunction;
  364.     dtRealData: FDataClass:=TRealData;
  365.   end;
  366. end;
  367.  
  368. function TContainer.GetDataType: TDataType;       {NOTE! ALL derivative types}
  369. begin                                                      {denotes dtCUSTOM!}
  370.   Result:=dtCustom;{default}                                       {=}
  371.   if FDataClass=TStringData then Result:=dtStringData;
  372.   if FDataClass=TFunction then Result:=dtFunction;
  373.   if FDataClass=TRealData then Result:=dtRealData;
  374. end;
  375.  
  376. procedure TContainer.SetFileName(FN: string);
  377. begin
  378.   if FUpdateCaption and (Owner is TForm)
  379.   then (Owner as TForm).Caption:=ExtractFileName(FN);
  380.   if FAutoLoad and (FFileName<>FN) then   {if name changed-try to reload data}
  381.   begin FFileName:=FN; LoadFromFile; end else FFileName:=FN;
  382. end;
  383.  
  384. procedure TContainer.Clear;               {delets & disposes off all elements}
  385. var I: integer; P: TData;
  386. begin
  387.   if not Assigned(FList) or (FList.Count=0) then Exit;
  388.   for I:=0 to FList.Count-1 do begin P:=FList[I]; P.Free; end;
  389.   FList.Clear;                                {^       can't use AS operator!}
  390.   Modified:=true;
  391. end;
  392.  
  393. procedure TContainer.LoadFromFile;                      {loads data from file}
  394. var F: system.text; P: TData;
  395. begin
  396.   try
  397.     Screen.Cursor:=crHourGlass; Clear;                   {prepare for loading}
  398.     system.Assign(F, FileName); system.Reset(F);       {open file for reading}
  399.     try
  400.       while not eof(F) do                           {read all lines in cycle:}
  401.       begin
  402.         P:=InitItem; if not assigned(P) then Break; P.LoadData(F); {!!! <>nil}
  403.         FList.Add(P); ShowProgress(FList.Count);
  404.       end;
  405.     finally
  406.       system.Close(F);               {Note: close only if open successfully!!}
  407.       Modified:=false;
  408.     end;
  409.   finally
  410.     Screen.Cursor:=crDefault;                       {restore cursor (always!)}
  411.   end;
  412. end;
  413.  
  414. procedure TContainer.SaveToFile(Backup: boolean);         {saves data to file}
  415. var F: system.text; I: integer; P: TData; BakName: string;
  416. begin
  417.   try
  418.     Screen.Cursor:=crHourGlass;
  419.     if Backup then                 {if old version exists, rename it to *.BAK}
  420.     begin
  421.       BakName:=ChangeFileExt(FileName, '.BAK');     {make name of backup copy}
  422.       if FileExists(BakName) then DeleteFile(BakName); {del old bak if exists}
  423.       RenameFile(FileName, BakName);                    {must be successfull!}
  424.     end;
  425.     system.Assign(F, FileName); system.ReWrite(F);     {open file for writing}
  426.     try
  427.       for I:=0 to FList.Count-1 do                                  {write...}
  428.       begin
  429.         P:=FList[I]; P.SaveData(F);
  430.         if FList.Count>1 then ShowProgress(Round(I/(FList.Count-1)*100.0));
  431.       end;                                    {^HERE may be integer overflow!}
  432.     finally
  433.       system.Close(F);
  434.       Modified:=false;
  435.     end;
  436.   finally
  437.     Screen.Cursor:=crDefault;                                        {restore}
  438.   end;
  439. end;
  440.  
  441. procedure TContainer.LoadFromStream(S: TStream);
  442. var I,N: longint; P: TData; T: TDataType;
  443. begin
  444.   Screen.Cursor:=crHourGlass;
  445.   S.ReadBuffer(T, SizeOf(T)); DataType:=T;                    {read data type}
  446.   S.ReadBuffer(N,SizeOf(N));                              {number of elements}
  447.   Clear;                                                          {clear list}
  448.   for I:=1 to N do                                             {read elements}
  449.   begin
  450.     P:=InitItem; if not Assigned(P) then Break;                    {!!! <>nil}
  451.     P.ReadData(S); FList.Add(P); if N<>0 then ShowProgress(Round(I/N*100.0));
  452.   end;
  453.   Modified:=false;
  454.   Screen.Cursor:=crDefault;
  455. end;
  456.  
  457. procedure TContainer.SaveToStream(S: TStream);
  458. var I: longint; P: TData; D: TDataType;
  459. begin
  460.   Screen.Cursor:=crHourGlass;
  461.   D:=DataType; S.WriteBuffer(D, SizeOf(TDataType));     {save type and number}
  462.   {S.WriteBuffer(FList.Count, SizeOf(integer));                  {of elements}
  463.                  {^ This doesn't work with Delphi16!}
  464.   I:=FList.Count; S.WriteBuffer(I, SizeOf(I));
  465.   for I:=0 to FList.Count-1 do                    {and elements themselves...}
  466.   begin
  467.     P:=FList[I]; P.WriteData(S);
  468.     if FList.Count>1 then ShowProgress(Round(I/(FList.Count-1)*100.0));
  469.   end;
  470.   Modified:=false;
  471.   Screen.Cursor:=crDefault;
  472. end;
  473.  
  474. procedure TContainer.SetModified(M: boolean);
  475. begin
  476.   FModified:=M;
  477.   if Assigned(FChanged) and not (csDestroying in ComponentState)
  478.   then FChanged(Self);      {^ prevent call when some comp-s have destroyed  }
  479. end;
  480.  
  481. procedure TContainer.Sort(BegLine,EndLine: integer; Descend: boolean);
  482.   procedure DoSort(BegLine,EndLine: integer; Descend: boolean);
  483.   var I,J: Integer; D: TData;
  484.   begin
  485.     I:=BegLine; J:=EndLine; D:=FList[(BegLine+EndLine) shr 1];
  486.     repeat
  487.       if Descend then                           {recoursive sorting algorithm}
  488.       begin
  489.         while FCompare(Self, FList[I], D)=crGreater do Inc(I);
  490.         while FCompare(Self, FList[J], D)=crLess do Dec(J);
  491.       end else
  492.       begin
  493.         while FCompare(Self, FList[I], D)=crLess do Inc(I);
  494.         while FCompare(Self, FList[J], D)=crGreater do Dec(J);
  495.       end;
  496.       if I<=J then begin Flist.Exchange(I, J); Inc(I); Dec(J); end;
  497.     until I>J;
  498.     if BegLine<J then DoSort(BegLine, J, Descend);
  499.     if I<EndLine then DoSort(I, EndLine, Descend);
  500.   end;
  501. begin
  502.   if (BegLine>=EndLine) or (not Assigned(FCompare)) then              {error!}
  503.   begin MessageDlg(errSort, mtError, [mbCancel], 0); Exit; end;
  504.   Screen.Cursor:=crHourglass;
  505.   DoSort(BegLine,EndLine,Descend);
  506.   Screen.Cursor:=crDefault;
  507.   Modified:=true;
  508. end;
  509.  
  510. procedure TContainer.DefineProperties(Filer: TFiler);
  511. begin
  512.   inherited DefineProperties(Filer);
  513.   Filer.DefineBinaryProperty('Data', LoadFromStream, SaveToStream, True);
  514. end;
  515.  
  516. function TContainer.Calibrate(R: TReal; Index,Key: integer): TReal;
  517. var D1,D2: TRealData; I,J,K: integer;
  518. begin
  519.   if R=DataCache then begin Result:=RowCache[Index]; Exit; end;
  520.   Result:=R; {default!!!}                           {^  value found in cache!}
  521.   if Items.Count<6 then Exit;                             {too short table!!!}
  522.   {main search}
  523.   D1:=Items.First; D2:=Items.Last;                               {check range}
  524.   if R<D1.RData[Key] then
  525.   begin Result:=D1.RData[Index]; Exit; end;       {Bad range! NOTE: no error!}
  526.   if R>D2.RData[Key] then
  527.   begin Result:=D2.RData[Index]; Exit; end;
  528.   I:=0; J:=Items.Count-1;
  529.   repeat                                   {find Xk with half division method}
  530.     D1:=Items[I+((J-I) div 2)];
  531.     if R<D1.RData[Key] then J:=I+(J-I) div 2 else I:=I+(J-I) div 2;
  532.   until J-I<2;
  533.   D1:=Items[I]; D2:=Items[J];
  534.   if D1.Size=D2.Size then for K:=1 to D1.Size do             {fill data cache}
  535.   RowCache[K]:=LineInterpolate(D1.RData[Key], D2.RData[Key],
  536.                                D1.RData[K], D2.RData[K], R);
  537.   Result:=RowCache[Index]; DataCache:=R;
  538. end;
  539.  
  540. procedure TContainer.Assign(Source: TPersistent);
  541. var I,N: integer; D: TData;
  542. begin
  543.   if not Assigned(FList) then Exit;// ???
  544.   if (Source is TContainer) or (Source is TStrings) then
  545.   begin
  546.     {Clear;} Screen.Cursor:=crHourglass;
  547.     try        // not Clear() - else OnChanged called twice (what is not good)
  548.       for I:=0 to Items.Count-1 do begin D:=Items[I]; D.Free; end;Items.Clear;
  549.       if Source is TContainer then N:=(Source as TContainer).Items.Count-1
  550.       else N:=(Source as TStrings).Count-1;
  551.       for I:=0 to N do
  552.       begin
  553.         D:=InitItem; if Assigned(D) then if Source is TContainer then
  554.         begin D.Copy((Source as TContainer).Items[I]); Items.Add(D); end
  555.         else begin D.Data:=(Source as TStrings)[I]; Items.Add(D); end;
  556.         if N<>0 then ShowProgress(Round(I/N*100.0));
  557.       end;
  558.     finally
  559.       Modified:=true; Screen.Cursor:=crDefault;   // modified - after changes!
  560.     end;
  561.   end else inherited;
  562. end;
  563.  
  564. {component registration - this unit may be used separately from dm2000}
  565. procedure Register;
  566. begin RegisterComponents('DM2000', [TContainer]); end;
  567.  
  568. end.
  569.