Subversion Repositories fastphp

Rev

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