home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d56 / RMCTL.ZIP / rmWordTree.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-22  |  25KB  |  1,000 lines

  1. {================================================================================
  2. Copyright (C) 1997-2001 Mills Enterprise
  3.  
  4. Unit     : rmWordTree
  5. Purpose  : The TrmWordTree is a non-visual component provides a dictionary type
  6.            word lookup interface.  You provide it with a list of words and then
  7.            you can verify words against it or it will provide a list of similar
  8.            words based on the soundex of the given word.
  9. Date     : 05-01-01
  10. Author   : Ryan J. Mills
  11. Version  : 1.80
  12. ================================================================================}
  13.  
  14. unit rmWordTree;
  15.  
  16. interface
  17.  
  18. {$I CompilerDefines.INC}
  19.  
  20. uses
  21.    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  22.  
  23. type
  24.    TAddMode = (taAddFirst, taAdd) ;
  25.    TNodeAttachMode = (naAdd, naAddFirst, naAddChild, naAddChildFirst, naInsert) ;
  26.  
  27.    PWTNodeInfo = ^TWTNodeInfo;
  28.    TWTNodeInfo = packed record
  29.       Letter: Char;
  30.       Count: Word;
  31.       Complete: Boolean;
  32.    end;
  33.  
  34.    TCustomrmWordTree = class;
  35.    TrmWordTreeNodes = class;
  36.    TrmWordTreeNode = class;
  37.  
  38.    TrmWordTreeNode = class(TPersistent)
  39.    private
  40.       FOwner: TrmWordTreeNodes;
  41.       FParent: TrmWordTreeNode;
  42.       FLetter: Char;
  43.       FComplete: boolean;
  44.       FChildList: TList;
  45.       FDeleting: Boolean;
  46.       function GetLevel: Integer;
  47.       procedure SetParent(Value: TrmWordTreeNode) ;
  48.       function GetChildren: Boolean;
  49.       function GetIndex: Integer;
  50.       function GetItem(Index: Integer) : TrmWordTreeNode;
  51.       function GetCount: Integer;
  52.       function GetWTTreeNonView: TCustomrmWordTree;
  53.       procedure ReadData(Stream: TStream; Info: PWTNodeInfo) ;
  54.       procedure SetItem(Index: Integer; Value: TrmWordTreeNode) ;
  55.       procedure WriteData(Stream: TStream; Info: PWTNodeInfo) ;
  56.       function IsEqual(Node: TrmWordTreeNode) : Boolean;
  57.       function getWord: string;
  58.    public
  59.       constructor Create(AOwner: TrmWordTreeNodes) ;
  60.       destructor Destroy; override;
  61.       procedure Assign(Source: TPersistent) ; override;
  62.       procedure Delete;
  63.       procedure DeleteChildren;
  64.       function GetFirstChild: TrmWordTreeNode;
  65.       function GetLastChild: TrmWordTreeNode;
  66.       function GetNext: TrmWordTreeNode;
  67.       function GetNextChild(Value: TrmWordTreeNode) : TrmWordTreeNode;
  68.       function GetNextSibling: TrmWordTreeNode;
  69.       function GetPrev: TrmWordTreeNode;
  70.       function GetPrevChild(Value: TrmWordTreeNode) : TrmWordTreeNode;
  71.       function getPrevSibling: TrmWordTreeNode;
  72.       function HasAsParent(Value: TrmWordTreeNode) : Boolean;
  73.       function IndexOf(Value: TrmWordTreeNode) : Integer;
  74.  
  75.       property Count: Integer read GetCount;
  76.       property Complete: boolean read FComplete write fComplete;
  77.       property Deleting: Boolean read FDeleting;
  78.       property HasChildren: Boolean read GetChildren;
  79.       property Index: Integer read GetIndex;
  80.       property Item[Index: Integer]: TrmWordTreeNode read GetItem write SetItem; default;
  81.       property Level: Integer read GetLevel;
  82.       property Owner: TrmWordTreeNodes read FOwner;
  83.       property Parent: TrmWordTreeNode read FParent write SetParent;
  84.       property WTTreeNonView: TCustomrmWordTree read GetWTTreeNonView;
  85.       property Letter: Char read FLetter write FLetter;
  86.       property Word : string read getWord;
  87.    end;
  88.  
  89.    TrmWordTreeNodes = class(TPersistent)
  90.    private
  91.       FOwner: TCustomrmWordTree;
  92.       FRootNodeList: TList;
  93.       function GetNodeFromIndex(Index: Integer) : TrmWordTreeNode;
  94.       procedure ReadData(Stream: TStream) ;
  95.       procedure WriteData(Stream: TStream) ;
  96.    protected
  97.       function InternalAddObject(Node: TrmWordTreeNode; const Letter: Char; Complete: boolean; AddMode: TAddMode) : TrmWordTreeNode;
  98.       procedure DefineProperties(Filer: TFiler) ; override;
  99.       function GetCount: Integer;
  100.       procedure SetItem(Index: Integer; Value: TrmWordTreeNode) ;
  101.    public
  102.       constructor Create(AOwner: TCustomrmWordTree) ;
  103.       destructor Destroy; override;
  104.       function AddChild(Node: TrmWordTreeNode; const Letter: Char) : TrmWordTreeNode;
  105.       function Add(Node: TrmWordTreeNode; const Letter: Char) : TrmWordTreeNode;
  106.       procedure Assign(Source: TPersistent) ; override;
  107.       procedure Clear;
  108.       procedure Delete(Node: TrmWordTreeNode) ;
  109.       function GetFirstNode: TrmWordTreeNode;
  110.       property Count: Integer read GetCount;
  111.       property Item[Index: Integer]: TrmWordTreeNode read GetNodeFromIndex; default;
  112.       property Owner: TCustomrmWordTree read FOwner;
  113.    end;
  114.  
  115. { TWTCustomrmWordTree }
  116.  
  117.    EWTTreeNonViewError = class(Exception) ;
  118.  
  119.    TCustomrmWordTree = class(TComponent)
  120.    private
  121.       FTreeNodes: TrmWordTreeNodes;
  122.       procedure SetrmWordTreeNodes(Value: TrmWordTreeNodes) ;
  123.    protected
  124.       function CreateNode: TrmWordTreeNode; virtual;
  125.       property Items: TrmWordTreeNodes read FTreeNodes write SeTrmWordTreeNodes;
  126.    public
  127.       constructor Create(AOwner: TComponent) ; override;
  128.       destructor Destroy; override;
  129.       function AddWord(word: string) : TrmWordTreeNode;
  130.       function IsWord(word: string) : Boolean;
  131.       function LocateWord(Word: string) : TrmWordTreeNode;
  132.       procedure LoadPartialMatches(Word: String; MatchList: TStrings);
  133.       procedure LoadSEMatches(Word: String; MatchList: TStrings);
  134.    end;
  135.  
  136.    TrmWordTree = class(TCustomrmWordTree)
  137.    private
  138.     { Private declarations }
  139.    protected
  140.     { Protected declarations }
  141.    public
  142.     { Public declarations }
  143.    published
  144.     { Published declarations }
  145.       property Items;
  146.    end;
  147.  
  148. procedure Register;
  149.  
  150. implementation
  151.  
  152. uses rmLibrary;
  153.  
  154. procedure Register;
  155. begin
  156.    RegisterComponents('rmControls', [TrmWordTree]) ;
  157. end;
  158.  
  159. procedure WTTreeNonViewError(const Msg: string) ;
  160. begin
  161.    raise EWTTreeNonViewError.Create(Msg) ;
  162. end;
  163.  
  164. constructor TrmWordTreeNode.Create(AOwner: TrmWordTreeNodes) ;
  165. begin
  166.    inherited Create;
  167.    FOwner := AOwner;
  168.    FChildList := TList.Create;
  169. end;
  170.  
  171. destructor TrmWordTreeNode.Destroy;
  172. begin
  173.    FDeleting := True;
  174.    FChildList.Free;
  175.    inherited Destroy;
  176. end;
  177.  
  178. function TrmWordTreeNode.GetWTTreeNonView: TCustomrmWordTree;
  179. begin
  180.    Result := Owner.Owner;
  181. end;
  182.  
  183. function TrmWordTreeNode.HasAsParent(Value: TrmWordTreeNode) : Boolean;
  184. begin
  185.    if Value <> Nil then
  186.    begin
  187.       if Parent = nil then
  188.          Result := False
  189.       else
  190.          if Parent = Value then
  191.          Result := True
  192.       else
  193.          Result := Parent.HasAsParent(Value) ;
  194.    end
  195.    else
  196.       Result := True;
  197. end;
  198.  
  199. function TrmWordTreeNode.GetChildren: Boolean;
  200. begin
  201.    Result := FChildList.Count > 0;
  202. end;
  203.  
  204. procedure TrmWordTreeNode.SetParent(Value: TrmWordTreeNode) ;
  205. begin
  206.    if (fParent <> nil) then
  207.       fParent.FChildList.delete(fParent.FChildList.indexOf(self) ) ;
  208.  
  209.    if value <> nil then
  210.    begin
  211.       FParent := Value;
  212.       if fParent.FChildList.indexof(self) = -1 then
  213.          fParent.FChildList.Add(self) ;
  214.    end;
  215. end;
  216.  
  217. function TrmWordTreeNode.GetNextSibling: TrmWordTreeNode;
  218. var
  219.    CurIdx: Integer;
  220.  
  221. begin
  222.    if Parent <> nil then
  223.    begin
  224.       CurIdx := Parent.FChildList.IndexOf(Self) ;
  225.       if (CurIdx + 1) < Parent.FChildList.Count then
  226.          Result := Parent.FChildList.Items[CurIdx + 1]
  227.       else
  228.          Result := nil;
  229.    end
  230.    else
  231.    begin
  232.       CurIdx := Owner.FRootNodeList.IndexOf(Self) ;
  233.       if (CurIdx + 1) < Owner.FRootNodeList.Count then
  234.          Result := Owner.FRootNodeList.Items[CurIdx + 1]
  235.       else
  236.          Result := nil;
  237.    end;
  238. end;
  239.  
  240. function TrmWordTreeNode.GetPrevSibling: TrmWordTreeNode;
  241. var
  242.    CurIdx: Integer;
  243. begin
  244.    if Parent <> nil then
  245.    begin
  246.       CurIdx := Parent.FChildList.IndexOf(Self) ;
  247.       if (CurIdx - 1) >= 0 then
  248.          Result := Parent.FChildList.Items[CurIdx - 1]
  249.       else
  250.          Result := nil;
  251.    end
  252.    else
  253.    begin
  254.       CurIdx := Owner.FRootNodeList.IndexOf(Self) ;
  255.       if (CurIdx - 1) >= Owner.FRootNodeList.Count then
  256.          Result := Owner.FRootNodeList.Items[CurIdx - 1]
  257.       else
  258.          Result := nil;
  259.    end;
  260. end;
  261.  
  262. function TrmWordTreeNode.GetNextChild(Value: TrmWordTreeNode) : TrmWordTreeNode;
  263. begin
  264.    if Value <> nil then
  265.       Result := Value.GetNextSibling
  266.    else
  267.       Result := nil;
  268. end;
  269.  
  270. function TrmWordTreeNode.GetPrevChild(Value: TrmWordTreeNode) : TrmWordTreeNode;
  271. begin
  272.    if Value <> nil then
  273.       Result := Value.GetPrevSibling
  274.    else
  275.       Result := nil;
  276. end;
  277.  
  278. function TrmWordTreeNode.GetFirstChild: TrmWordTreeNode;
  279. begin
  280.    if FChildList.Count > 0 then
  281.       Result := FChildList.Items[0]
  282.    else
  283.       Result := nil;
  284. end;
  285.  
  286. function TrmWordTreeNode.GetLastChild: TrmWordTreeNode;
  287. begin
  288.    if FChildList.Count > 0 then
  289.       Result := FChildList.Items[FChildList.Count - 1]
  290.    else
  291.       Result := nil;
  292. end;
  293.  
  294. function TrmWordTreeNode.GetNext: TrmWordTreeNode;
  295. var
  296.    N: TrmWordTreeNode;
  297.    P: TrmWordTreeNode;
  298.  
  299. begin
  300.    if HasChildren then
  301.       N := GetFirstChild
  302.    else
  303.    begin
  304.       N := GetNextSibling;
  305.       if N = nil then
  306.       begin
  307.          P := Parent;
  308.          while P <> nil do
  309.          begin
  310.             N := P.GetNextSibling;
  311.             if N <> nil then
  312.                Break;
  313.             P := P.Parent;
  314.          end;
  315.       end;
  316.    end;
  317.    Result := N;
  318. end;
  319.  
  320. function TrmWordTreeNode.GetPrev: TrmWordTreeNode;
  321. var
  322.    Node: TrmWordTreeNode;
  323.  
  324. begin
  325.    Result := GetPrevSibling;
  326.    if Result <> nil then
  327.    begin
  328.       Node := Result;
  329.       repeat
  330.          Result := Node;
  331.          Node := Result.GetLastChild;
  332.       until Node = nil;
  333.    end
  334.    else
  335.       Result := Parent;
  336. end;
  337.  
  338. function TrmWordTreeNode.GetIndex: Integer;
  339. var
  340.    node : TrmWordTreeNode;
  341. begin
  342.    Result := -1;
  343.    Node := parent;
  344.    if Node = nil then
  345.    begin
  346.       if fowner <> nil then
  347.          FOwner.FRootNodeList.indexof(self)
  348.    end
  349.    else
  350.       result := parent.FChildList.indexof(self);
  351. end;
  352.  
  353. function TrmWordTreeNode.GetItem(Index: Integer) : TrmWordTreeNode;
  354. begin
  355.    if (index >= 0) and (index < FChildList.count) then
  356.       Result := fchildlist[index]
  357.    else
  358.    begin
  359.       result := nil;
  360.       WTTreeNonViewError('List Index Out of Bounds') ;
  361.    end;
  362. end;
  363.  
  364. procedure TrmWordTreeNode.SetItem(Index: Integer; Value: TrmWordTreeNode) ;
  365. begin
  366.    item[Index].Assign(Value) ;
  367. end;
  368.  
  369. function TrmWordTreeNode.IndexOf(Value: TrmWordTreeNode) : Integer;
  370. begin
  371.    Result := fChildList.indexof(Value) ;
  372. end;
  373.  
  374. function TrmWordTreeNode.GetCount: Integer;
  375. begin
  376.    result := FChildList.count;
  377. end;
  378.  
  379. function TrmWordTreeNode.GetLevel: Integer;
  380. var
  381.    Node: TrmWordTreeNode;
  382.  
  383. begin
  384.    Result := 0;
  385.    Node := Parent;
  386.    while Node <> nil do
  387.    begin
  388.       Inc(Result) ;
  389.       Node := Node.Parent;
  390.    end;
  391. end;
  392.  
  393. procedure TrmWordTreeNode.Delete;
  394. begin
  395.    if HasChildren then
  396.       DeleteChildren;
  397.  
  398.    if Parent <> nil then
  399.    begin
  400.       Parent.FChildList.Delete(Parent.FChildList.IndexOf(Self) ) ;
  401.       Parent.FChildList.Pack;
  402.    end
  403.    else
  404.    begin
  405.       Owner.FRootNodeList.Delete(Owner.FRootNodeList.IndexOf(Self) ) ;
  406.       Owner.FRootNodeList.Pack;
  407.    end;
  408.    Free;
  409. end;
  410.  
  411. procedure TrmWordTreeNode.DeleteChildren;
  412. var
  413.    Node: TrmWordTreeNode;
  414.  
  415. begin
  416.    Node := GetFirstChild;
  417.    while Node <> nil do
  418.    begin
  419.       Node.Delete;
  420.       Node := GetFirstChild;
  421.    end;
  422. end;
  423.  
  424. procedure TrmWordTreeNode.ReadData(Stream: TStream; Info: PWTNodeInfo) ;
  425. var
  426.    I, Size, ItemCount: Integer;
  427.  
  428. begin
  429.    Stream.ReadBuffer(Size, SizeOf(Size) ) ;
  430.    Stream.ReadBuffer(Info^, Size) ;
  431.    Letter := Info^.Letter;
  432.    ItemCount := Info^.Count;
  433.    Complete := Info^.Complete;
  434.    for I := 0 to ItemCount - 1 do
  435.       Owner.AddChild(Self, #0) .ReadData(Stream, Info) ;
  436. end;
  437.  
  438. procedure TrmWordTreeNode.WriteData(Stream: TStream; Info: PWTNodeInfo) ;
  439. var
  440.    I,
  441.       Size,
  442.       ItemCount: Integer;
  443.  
  444. begin
  445.    Size := SizeOf(TWTNodeInfo) ;
  446.    Info^.Letter := Letter;
  447.    ItemCount := Count;
  448.    Info^.Count := ItemCount;
  449.    Info^.Complete := Complete;
  450.    Stream.WriteBuffer(Size, SizeOf(Size) ) ;
  451.    Stream.WriteBuffer(Info^, Size) ;
  452.    for I := 0 to ItemCount - 1 do
  453.       Item[I].WriteData(Stream, Info) ;
  454. end;
  455.  
  456. { TrmWordTreeNodes }
  457.  
  458. constructor TrmWordTreeNodes.Create(AOwner: TCustomrmWordTree) ;
  459. begin
  460.    inherited Create;
  461.    FOwner := AOwner;
  462.    FRootNodeList := TList.Create;
  463. end;
  464.  
  465. destructor TrmWordTreeNodes.Destroy;
  466. begin
  467.    Clear;
  468.    FRootNodeList.Free;
  469.    inherited Destroy;
  470. end;
  471.  
  472. function TrmWordTreeNodes.GetCount: Integer;
  473. var
  474.    N: TrmWordTreeNode;
  475. begin
  476.    N := GetFirstNode;
  477.    Result := 0;
  478.    while N <> nil do
  479.    begin
  480.       Result := Result + 1;
  481.       N := N.GetNext;
  482.    end;
  483. end;
  484.  
  485. procedure TrmWordTreeNodes.Delete(Node: TrmWordTreeNode) ;
  486. begin
  487.    Node.Delete;
  488. end;
  489.  
  490. procedure TrmWordTreeNodes.Clear;
  491. var
  492.    N: TrmWordTreeNode;
  493.  
  494. begin
  495.    N := GetFirstNode;
  496.    While N <> nil do
  497.    begin
  498.       N.Delete;
  499.       N := GetFirstNode;
  500.    end;
  501. end;
  502.  
  503. function TrmWordTreeNodes.AddChild(Node: TrmWordTreeNode; const Letter: char) : TrmWordTreeNode;
  504. begin
  505.    Result := InternalAddObject(Node, Letter, False, taAdd) ;
  506. end;
  507.  
  508. function TrmWordTreeNodes.Add(Node: TrmWordTreeNode; const Letter: char) : TrmWordTreeNode;
  509. begin
  510.    if Node <> nil then Node := Node.Parent;
  511.    Result := InternalAddObject(Node, Letter, False, taAdd) ;
  512. end;
  513.  
  514. function TrmWordTreeNodes.InternalAddObject(Node: TrmWordTreeNode; const Letter: char;
  515.    Complete: boolean; AddMode: TAddMode) : TrmWordTreeNode;
  516. begin
  517.    Result := Owner.CreateNode;
  518.    try
  519.       case AddMode of
  520.          taAddFirst:
  521.             begin
  522.                if Node = nil then
  523.                begin
  524.                   FRootNodeList.Insert(0, Result) ;
  525.                   Result.Parent := nil;
  526.                end
  527.                else
  528.                begin
  529.                   Node.FChildList.Insert(0, Result) ;
  530.                   Result.Parent := Node;
  531.                end;
  532.                try
  533.                   Result.Complete := complete;
  534.                   Result.Letter := Letter;
  535.                except
  536.                   raise;
  537.                end;
  538.             end;
  539.  
  540.          taAdd:
  541.             begin
  542.                if Node = nil then
  543.                begin
  544.                   FRootNodeList.Add(Result) ;
  545.                   Result.Parent := nil;
  546.                end
  547.                else
  548.                begin
  549.                   Node.FChildList.Add(Result) ;
  550.                   Result.Parent := Node;
  551.                end;
  552.                try
  553.                   Result.Complete := complete;
  554.                   Result.Letter := Letter;
  555.                except
  556.                   raise;
  557.                end;
  558.             end;
  559.       end;
  560.    except
  561.       raise;
  562.    end;
  563. end;
  564.  
  565. function TrmWordTreeNodes.GetFirstNode: TrmWordTreeNode;
  566. begin
  567.    if FRootNodeList.Count = 0 then
  568.       Result := nil
  569.    else
  570.       Result := FRootNodeList.Items[0];
  571. end;
  572.  
  573. function TrmWordTreeNodes.GetNodeFromIndex(Index: Integer) : TrmWordTreeNode;
  574. var
  575.    I: Integer;
  576. begin
  577.    Result := GetFirstNode;
  578.    I := Index;
  579.    while (I <> 0) and (Result <> nil) do
  580.    begin
  581.       Result := Result.GetNext;
  582.       Dec(I) ;
  583.    end;
  584.    if Result = nil then
  585.       WTTreeNonViewError('Index out of range') ;
  586. end;
  587.  
  588. procedure TrmWordTreeNodes.SetItem(Index: Integer; Value: TrmWordTreeNode) ;
  589. begin
  590.    GetNodeFromIndex(Index) .Assign(Value) ;
  591. end;
  592.  
  593. procedure TrmWordTreeNodes.Assign(Source: TPersistent) ;
  594. var
  595.    TreeNodes: TrmWordTreeNodes;
  596.    MemStream: TMemoryStream;
  597. begin
  598.    if Source is TrmWordTreeNodes then
  599.    begin
  600.       TreeNodes := TrmWordTreeNodes(Source) ;
  601.       Clear;
  602.       MemStream := TMemoryStream.Create;
  603.       try
  604.          TreeNodes.WriteData(MemStream) ;
  605.          MemStream.Position := 0;
  606.          ReadData(MemStream) ;
  607.       finally
  608.          MemStream.Free;
  609.       end;
  610.    end
  611.    else inherited Assign(Source) ;
  612. end;
  613.  
  614. procedure TrmWordTreeNodes.DefineProperties(Filer: TFiler) ;
  615.  
  616.    function WriteNodes: Boolean;
  617.    var
  618.       I: Integer;
  619.       Nodes: TrmWordTreeNodes;
  620.    begin
  621.       Nodes := TrmWordTreeNodes(Filer.Ancestor) ;
  622.       if Nodes = nil then
  623.          Result := Count > 0
  624.       else if Nodes.Count <> Count then
  625.          Result := True
  626.       else
  627.       begin
  628.          Result := False;
  629.          for I := 0 to Count - 1 do
  630.          begin
  631.             Result := not Item[I].IsEqual(Nodes[I]) ;
  632.             if Result then Break;
  633.          end
  634.       end;
  635.    end;
  636.  
  637. begin
  638.    inherited DefineProperties(Filer) ;
  639.    Filer.DefineBinaryProperty('Data', ReadData, WriteData, WriteNodes) ;
  640. end;
  641.  
  642. procedure TrmWordTreeNodes.ReadData(Stream: TStream) ;
  643. var
  644.    I, Count: Integer;
  645.    Info: TWTNodeInfo;
  646.  
  647. begin
  648.    Clear;
  649.    Stream.ReadBuffer(Count, SizeOf(Count) ) ;
  650.    for I := 0 to Count - 1 do
  651.       Add(nil, #0) .ReadData(Stream, @Info) ;
  652. end;
  653.  
  654. procedure TrmWordTreeNodes.WriteData(Stream: TStream) ;
  655. var
  656.    I: Integer;
  657.    Node: TrmWordTreeNode;
  658.    Info: TWTNodeInfo;
  659.  
  660. begin
  661.    I := 0;
  662.    Node := GetFirstNode;
  663.    while Node <> nil do
  664.    begin
  665.       Inc(I) ;
  666.       Node := Node.GetNextSibling;
  667.    end;
  668.    Stream.WriteBuffer(I, SizeOf(I) ) ;
  669.    Node := GetFirstNode;
  670.    while Node <> nil do
  671.    begin
  672.       Node.WriteData(Stream, @Info) ;
  673.       Node := Node.GetNextSibling;
  674.    end;
  675. end;
  676.  
  677. { TCustomrmWordTree }
  678.  
  679. constructor TCustomrmWordTree.Create(AOwner: TComponent) ;
  680. begin
  681.    inherited Create(AOwner) ;
  682.    FTreeNodes := TrmWordTreeNodes.Create(Self) ;
  683. end;
  684.  
  685. destructor TCustomrmWordTree.Destroy;
  686. begin
  687.    Items.Free;
  688.    inherited Destroy;
  689. end;
  690.  
  691. procedure TCustomrmWordTree.SetrmWordTreeNodes(Value: TrmWordTreeNodes) ;
  692. begin
  693.    Items.Assign(Value) ;
  694. end;
  695.  
  696. function TCustomrmWordTree.CreateNode: TrmWordTreeNode;
  697. begin
  698.    Result := TrmWordTreeNode.Create(Items) ;
  699. end;
  700.  
  701. function TrmWordTreeNode.IsEqual(Node: TrmWordTreeNode) : Boolean;
  702. begin
  703.    Result := (Letter = Node.Letter) and (Complete = Node.Complete) ;
  704. end;
  705.  
  706. procedure TrmWordTreeNode.Assign(Source: TPersistent) ;
  707. var
  708.    Node: TrmWordTreeNode;
  709.  
  710. begin
  711.    if Source is TrmWordTreeNode then
  712.    begin
  713.       Node := TrmWordTreeNode(Source) ;
  714.       Letter := Node.Letter;
  715.       Complete := Node.Complete;
  716.    end
  717.    else
  718.       inherited Assign(Source) ;
  719. end;
  720.  
  721. function TCustomrmWordTree.AddWord(word: string) : TrmWordTreeNode;
  722. var
  723.    wNode, wLastNode: TrmWordTreeNode;
  724.    wIndex, wLen: integer;
  725. begin
  726.    result := nil;
  727.    if Word = '' then
  728.       exit;
  729.  
  730.   wNode := LocateWord(word) ;
  731.  
  732.    if wNode = nil then
  733.    begin
  734.  
  735.       wIndex := 1;
  736.       wLen := Length(word);
  737.       wLastNode := nil;
  738.       wNode := FTreeNodes.GetFirstNode;
  739.       while (wNode <> nil) and (wIndex <= wLen) do
  740.       begin
  741.          wLastNode := wNode;
  742.          if wNode.Letter = Word[wIndex] then
  743.          begin
  744.             if wIndex < wLen then
  745.             begin
  746.                wNode := wNode.GetFirstChild;
  747.                inc(wIndex) ;
  748.             end
  749.             else
  750.                wNode := nil;
  751.          end
  752.          else
  753.          begin
  754.             if wNode.GetNextSibling = nil then
  755.             begin
  756.                wLastNode := wNode.parent;
  757.                wNode := nil;
  758.             end
  759.             else
  760.                wNode := wNode.GetNextSibling;
  761.          end;
  762.       end;
  763.  
  764.       if (wIndex <= wLen) then
  765.       begin
  766.          if wIndex > 1 then
  767.             wNode := wLastNode
  768.          else
  769.             wNode := nil;
  770.          while wIndex <= wLen do
  771.          begin
  772.             wNode := fTreeNodes.AddChild(wNode, word[wIndex]) ;
  773.             inc(wIndex) ;
  774.          end;
  775.          wNode.Complete := true;
  776.       end;
  777.    end
  778.    else
  779.       wNode.Complete := true;
  780.  
  781.    result := wNode;
  782. end;
  783.  
  784. function TCustomrmWordTree.IsWord(word: string) : Boolean;
  785. var
  786.    wNode : TrmWordTreeNode;
  787. begin
  788.    wNode := locateWord(word);
  789.    result := (wNode <> nil) and (wNode.Complete);
  790. end;
  791.  
  792. function TCustomrmWordTree.LocateWord(Word: string) : TrmWordTreeNode;
  793. var
  794.    wNode, wLastNode: TrmWordTreeNode;
  795.    wIndex, wLen: integer;
  796. begin
  797.    result := nil;
  798.    if Word = '' then
  799.       exit;
  800.  
  801.    wIndex := 1;
  802.    wLen := Length(word);
  803.    wLastNode := nil;
  804.    wNode := FTreeNodes.GetFirstNode;
  805.    while (wNode <> nil) and (wIndex <= wLen) do
  806.    begin
  807.       wLastNode := wNode;
  808.       if wNode.Letter = Word[wIndex] then
  809.       begin
  810.          if wIndex < wLen then
  811.          begin
  812.             wNode := wNode.GetFirstChild;
  813.             inc(wIndex) ;
  814.          end
  815.          else
  816.             wNode := nil;
  817.       end
  818.       else
  819.          wNode := wNode.GetNextSibling;
  820.    end;
  821.    if assigned(wLastNode) then
  822.    begin
  823.       if wLastNode.Complete and (wLastNode.Word = Word) then
  824.          result := wLastNode;
  825.    end
  826. end;
  827.  
  828. procedure TCustomrmWordTree.LoadPartialMatches(Word: String; MatchList: TStrings) ;
  829.  
  830.    procedure RecurseNodes(Node: TrmWordTreeNode) ;
  831.    var
  832.       wChild: TrmWordTreeNode;
  833.    begin
  834.       if Node <> nil then
  835.       begin
  836.          if Node.Complete then
  837.             MatchList.Add(Node.Word) ;
  838.  
  839.          wChild := Node.GetFirstChild;
  840.          while wChild <> nil do
  841.          begin
  842.             RecurseNodes(wChild) ;
  843.             wChild := Node.GetNextChild(wChild) ;
  844.          end;
  845.       end;
  846.    end;
  847.  
  848. var
  849.    wLastNode, wNode: TrmWordTreeNode;
  850.    wLen, wIndex: integer;
  851. begin
  852.    MatchList.clear;
  853.  
  854.    wNode := FTreeNodes.GetFirstNode;
  855.    if Word = '' then
  856.    begin
  857.       While wNode <> nil do
  858.       begin
  859.          RecurseNodes(wNode) ;
  860.          wNode := wNode.GetNextSibling;
  861.       end;
  862.    end
  863.    else
  864.    begin
  865.       wIndex := 1;
  866.       wLen := Length(word);
  867.       wLastNode := nil;
  868.       while (wNode <> nil) and (wIndex <= wLen) do
  869.       begin
  870.          wLastNode := wNode;
  871.          if wNode.Letter = Word[wIndex] then
  872.          begin
  873.             if wIndex < wLen then
  874.             begin
  875.                wNode := wNode.GetFirstChild;
  876.                inc(wIndex) ;
  877.             end
  878.             else
  879.                wNode := nil;
  880.          end
  881.          else
  882.             wNode := wNode.GetNextSibling;
  883.       end;
  884.       if assigned(wLastNode) then
  885.          RecurseNodes(wLastNode) ;
  886.    end;
  887. end;
  888.  
  889. function TrmWordTreeNode.getWord: string;
  890. var
  891.    wNode : TrmWordTreeNode;
  892. begin
  893.    result := '';
  894.    
  895.    if not Complete then
  896.       exit;
  897.  
  898.    wNode := self;
  899.    while wNode <> nil do
  900.    begin
  901.        result := wNode.letter + result;
  902.        wNode := wNode.Parent;
  903.    end;
  904. end;
  905.  
  906. procedure TCustomrmWordTree.LoadSEMatches(Word: String; MatchList: TStrings);
  907. var
  908.    wNode: TrmWordTreeNode;
  909.    wChar : char;
  910.    wWordSE : string;
  911.    wSELen : integer;
  912.    wloop : integer;
  913.    wSEChar : string;
  914.    wWordLen : integer;
  915.    wUpWord : string;
  916.  
  917.  
  918.    function TestWord(NodeWord:string):boolean;
  919.    var
  920.       wCount : integer;
  921.       wloop : integer;
  922.    begin
  923.       result := false;
  924.  
  925.       if uppercase(NodeWord) = wUpWord then
  926.          exit;
  927.  
  928.       if (wWordSE = soundex(NodeWord, true, wSELen)) then
  929.       begin
  930.          wcount := 0;
  931.          for wloop := 1 to wSELen do
  932.          begin
  933.             if pos(wSEChar[wloop], NodeWord) = 0 then
  934.                inc(wcount);
  935.          end;
  936.          result := (wCount < 2) and (abs(length(NodeWord) - wWordLen) < 2);
  937.       end;
  938.    end;
  939.  
  940.    procedure RecurseNodes(Node: TrmWordTreeNode) ;
  941.    var
  942.       wChild: TrmWordTreeNode;
  943.    begin
  944.       if Node <> nil then
  945.       begin
  946.          if Node.Complete and TestWord(Node.word) then
  947.             MatchList.Add(Node.Word) ;
  948.  
  949.          wChild := Node.GetFirstChild;
  950.          while wChild <> nil do
  951.          begin
  952.             RecurseNodes(wChild) ;
  953.             wChild := Node.GetNextChild(wChild) ;
  954.          end;
  955.       end;
  956.    end;
  957.  
  958. begin
  959.    MatchList.Clear;
  960.  
  961.    word := trim(word);
  962.  
  963.    if word = '' then
  964.       exit;
  965.  
  966.    wSELen := 0;
  967.    wloop := length(word);
  968.    wSEChar := '';
  969.    while wloop > 1 do
  970.    begin
  971.       if not (word[wloop] in ['A','E','I','O','U']) then
  972.       begin
  973.          inc(wSELen);
  974.          if (wSEChar = '') or ((wSEChar <> '') and (word[wloop] <> wSEChar[1])) then
  975.             wSEChar := word[wloop] + wSEChar;
  976.       end;
  977.  
  978.       dec(wLoop);
  979.    end;
  980.  
  981.    if wSELen < 4 then
  982.       wSELen := 4;
  983.  
  984.    wWordSE := Soundex(Word, true, wSELen);
  985.    wChar := word[1];
  986.    wNode := FTreeNodes.GetFirstNode;
  987.    wWordLen := length(word);
  988.    wUpWord := uppercase(word);
  989.  
  990.    While wNode <> nil do
  991.    begin
  992.       if lowercase(wNode.Letter) = lowercase(wChar) then
  993.          RecurseNodes(wNode);
  994.       wNode := wNode.GetNextSibling;
  995.    end;
  996. end;
  997.  
  998. end.
  999.  
  1000.