Subversion Repositories fastphp

Rev

Rev 27 | Rev 33 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit FastPHPTreeView;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Classes, ComCtrls;
  7.  
  8. (*
  9.  
  10. <FastPHPData>    ::= <FastPHPData100> .
  11.  
  12. Version 1.00:
  13. <FastPHPData100> ::= "FAST100!" (<Nodes> <Exit> | <Exit>) .
  14. <Nodes>          ::= <Node> | <Nodes> <Node> .
  15. <Node>           ::= <LeafNode> | <LeafNode> <IncreaseLevel> <Nodes> <DecreaseLevel> .
  16. <LeafNode>       ::= "N" <Icon(8)> <LineNo(8)> <DescLen(4)> <Desc> .
  17. <IncreaseLevel>  ::= "I" .
  18. <DecreaseLevel>  ::= "D" .
  19. <Exit>           ::= "X" .
  20.  
  21. *)
  22.  
  23. type
  24.   TTreeViewFastPHP = class helper for TTreeView
  25.   private
  26.     //FPrevFastPHPData: string;
  27.     class function Read(var ptr: PChar; len: integer): string; inline;
  28.     procedure Rec100(tn: TTreeNode; var ptr: PChar);
  29.   protected
  30.     procedure DoFillWithFastPHPData(ptr: PChar);
  31.   public
  32.     procedure FillWithFastPHPData(data: string);
  33.   end;
  34.  
  35.   EFastNodeException = class(Exception);
  36.  
  37. implementation
  38.  
  39. uses
  40.   StrUtils;
  41.  
  42. const
  43.   LEN_MAGIC   = 8;
  44.   LEN_ICON    = 8;
  45.   LEN_LINENO  = 8;
  46.   LEN_DESCLEN = 4;
  47.  
  48. procedure TTreeViewFastPHP.DoFillWithFastPHPData(ptr: PChar);
  49. var
  50.   s: String;
  51.   tn, tmp: TTreeNode;
  52.   expanded: TStringList;
  53.   selected, magic: string;
  54.   i: integer;
  55. begin
  56.   selected := '';
  57.   expanded := TStringList.Create;
  58.   Self.Items.BeginUpdate;
  59.   try
  60.     {$REGION 'Remember our current state (selected and expanded flags)'}
  61.     for i := 0 to Self.Items.Count-1 do
  62.     begin
  63.       tn := Self.Items.Item[i];
  64.       s := tn.Text;
  65.       tmp := tn.Parent;
  66.       while tmp <> nil do
  67.       begin
  68.         s := tmp.Text + #0 + s;
  69.         tmp := tmp.Parent;
  70.       end;
  71.       if tn.Selected then selected := s;
  72.       if tn.Expanded and tn.HasChildren then expanded.Add(s);
  73.     end;
  74.     {$ENDREGION}
  75.  
  76.     {$REGION 'Update the treeview'}
  77.     Self.Items.Clear;
  78.     magic := Read(ptr, LEN_MAGIC);
  79.     if magic = 'FAST100!' then
  80.       Rec100(nil, ptr)
  81.     else
  82.       raise EFastNodeException.CreateFmt('FastNode version "%s" not supported.', [magic]);
  83.     {$ENDREGION}
  84.  
  85.     {$REGION 'Recover the previous current state (selected and expanded flags)'}
  86.     for i := 0 to Self.Items.Count-1 do
  87.     begin
  88.       tn := Self.Items.Item[i];
  89.       s := tn.Text;
  90.       tmp := tn.Parent;
  91.       while tmp <> nil do
  92.       begin
  93.         s := tmp.Text + #0 + s;
  94.         tmp := tmp.Parent;
  95.       end;
  96.       if selected = s then tn.Selected := true;
  97.       if expanded.IndexOf(s) >= 0 then tn.Expand(false);
  98.     end;
  99.     {$ENDREGION}
  100.   finally
  101.     expanded.Free;
  102.     Self.Items.EndUpdate;
  103.   end;
  104. end;
  105.  
  106. procedure TTreeViewFastPHP.FillWithFastPHPData(data: string);
  107. begin
  108.   //if FPrevFastPHPData = data then exit;
  109.   //FPrevFastPHPData := data;
  110.  
  111.   data := Trim(data);
  112.   if not EndsStr('X', data) then raise EFastNodeException.Create('FastNode string must end with "X"');
  113.  
  114.   DoFillWithFastPHPData(PChar(data));
  115. end;
  116.  
  117. class function TTreeViewFastPHP.Read(var ptr: PChar; len: integer): string;
  118. begin
  119.   result := Copy(string(ptr), 1, len);
  120.   inc(ptr, len);
  121. end;
  122.  
  123. procedure TTreeViewFastPHP.Rec100(tn: TTreeNode; var ptr: PChar);
  124. var
  125.   typ, icon, lineno, len, caption: string;
  126.   lastTn: TTreeNode;
  127. begin
  128.   try
  129.     lastTn := nil;
  130.     while true do
  131.     begin
  132.       repeat
  133.         typ := Read(ptr, 1);
  134.       until Trim(typ) <> '';
  135.       if typ = 'N' then // new node
  136.       begin
  137.         icon   := Read(ptr, LEN_ICON);
  138.         lineno := Read(ptr, LEN_LINENO);
  139.         len    := Read(ptr, LEN_DESCLEN);
  140.         caption := Read(ptr, StrToInt(len));
  141.         if tn = nil then
  142.           lastTn := Self.Items.Add(nil, caption)
  143.         else
  144.           lastTn := Self.Items.AddChild(tn, caption);
  145.         lastTn.Data := Pointer(StrToInt(lineno)); // TODO: is this good?
  146.       end
  147.       else if typ = 'I' then // increase level
  148.       begin
  149.         if LastTn = nil then raise EFastNodeException.Create('Fast100: Increase command requires previous node');
  150.         Rec100(lastTn, ptr);
  151.       end
  152.       else if typ = 'D' then Exit // decrease level
  153.       else if typ = 'X' then Abort // exit
  154.       else raise EFastNodeException.CreateFmt('Fast100: Command "%s" unknown', [typ]);
  155.     end;
  156.   except
  157.     on E: EAbort do
  158.       exit
  159.     else
  160.       raise;
  161.   end;
  162. end;
  163.  
  164. end.
  165.