Subversion Repositories fastphp

Rev

Rev 34 | Rev 36 | 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, Windows;
  43.  
  44. const
  45.   LEN_MAGIC   = 8;
  46.   LEN_ICON    = 8;
  47.   LEN_LINENO  = 8;
  48.   LEN_DESCLEN = 4;
  49.  
  50. {$EXTERNALSYM LockWindowUpdate}
  51. function LockWindowUpdate(hWndLock: HWND): BOOL; stdcall; external user32 name 'LockWindowUpdate';
  52.  
  53. procedure TTreeViewFastPHP.DoFillWithFastPHPData(ptr: PChar);
  54.  
  55.   function _NodeID(tn: TTreeNode): string;
  56.   var
  57.     tmp: TTreeNode;
  58.   begin
  59.     // Attention: This function requires that the tree node items are unique
  60.     //            e.g. Class1->function1() is unique
  61.     result := tn.Text;
  62.     tmp := tn.Parent;
  63.     while tmp <> nil do
  64.     begin
  65.       result := tmp.Text + #0 + result;
  66.       tmp := tmp.Parent;
  67.     end;
  68.   end;
  69.  
  70. var
  71.   s: String;
  72.   tn: TTreeNode;
  73.   expanded: TStringList;
  74.   selected, magic: string;
  75.   horPos, verPos: integer;
  76.   i: integer;
  77. begin
  78.   selected := '';
  79.   expanded := TStringList.Create;
  80.   horPos := GetScrollPos(Handle, SB_HORZ);
  81.   verPos := GetScrollPos(Handle, SB_VERT);
  82.   LockWindowUpdate(Parent.Handle); // Parent is better choice for FastPHP... but for other applications it might be wrong?
  83.   Self.Items.BeginUpdate;
  84.   try
  85.     {$REGION 'Remember our 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 := _NodeID(tn);
  90.       if tn.Selected then selected := s;
  91.       if tn.Expanded and tn.HasChildren then expanded.Add(s);
  92.     end;
  93.     {$ENDREGION}
  94.  
  95.     {$REGION 'Update the treeview'}
  96.     Self.Items.Clear;
  97.     magic := Read(ptr, LEN_MAGIC);
  98.     if magic = 'FAST100!' then
  99.       Rec100(nil, ptr)
  100.     else
  101.       raise EFastNodeException.CreateFmt('FastNode version "%s" not supported.', [magic]);
  102.     {$ENDREGION}
  103.  
  104.     {$REGION 'Recover the previous current state (selected and expanded flags)'}
  105.     for i := 0 to Self.Items.Count-1 do
  106.     begin
  107.       tn := Self.Items.Item[i];
  108.       s := _NodeID(tn);
  109.       if selected = s then tn.Selected := true;
  110.       if expanded.IndexOf(s) >= 0 then tn.Expand(false);
  111.     end;
  112.     {$ENDREGION}
  113.   finally
  114.     Self.Items.EndUpdate;
  115.     LockWindowUpdate(0);
  116.  
  117.     // TODO: Bug! When the user keeps pressing the scrollbar, the program hangs and locks up
  118.     SetScrollPos(Handle, SB_HORZ, horPos, false);
  119.     SetScrollPos(Handle, SB_VERT, verPos, false);
  120.  
  121.     expanded.Free;
  122.   end;
  123. end;
  124.  
  125. procedure TTreeViewFastPHP.FillWithFastPHPData(data: string);
  126. begin
  127.   //if FPrevFastPHPData = data then exit;
  128.   //FPrevFastPHPData := data;
  129.  
  130.   data := Trim(data);
  131.   if not EndsStr('X', data) then raise EFastNodeException.Create('FastNode string must end with "X"');
  132.  
  133.   DoFillWithFastPHPData(PChar(data));
  134. end;
  135.  
  136. class function TTreeViewFastPHP.Read(var ptr: PChar; len: integer): string;
  137. begin
  138.   result := Copy(string(ptr), 1, len);
  139.   inc(ptr, len);
  140. end;
  141.  
  142. procedure TTreeViewFastPHP.Rec100(tn: TTreeNode; var ptr: PChar);
  143. var
  144.   typ, icon, lineno, len, caption: string;
  145.   lastTn: TTreeNode;
  146. begin
  147.   try
  148.     lastTn := nil;
  149.     while true do
  150.     begin
  151.       repeat
  152.         typ := Read(ptr, 1);
  153.       until Trim(typ) <> '';
  154.       if typ = 'N' then // new node
  155.       begin
  156.         icon   := Read(ptr, LEN_ICON);
  157.         lineno := Read(ptr, LEN_LINENO);
  158.         len    := Read(ptr, LEN_DESCLEN);
  159.         caption := Utf8Decode(Read(ptr, StrToInt(len)));
  160.         if tn = nil then
  161.           lastTn := Self.Items.Add(nil, caption)
  162.         else
  163.           lastTn := Self.Items.AddChild(tn, caption);
  164.         // lastTn.ImageIndex := // TODO
  165.         lastTn.Data := Pointer(StrToInt(lineno)); // TODO: is this good?
  166.       end
  167.       else if typ = 'I' then // increase level
  168.       begin
  169.         if LastTn = nil then raise EFastNodeException.Create('Fast100: Increase command requires previous node');
  170.         Rec100(lastTn, ptr);
  171.       end
  172.       else if typ = 'D' then Exit // decrease level
  173.       else if typ = 'X' then Abort // exit
  174.       else raise EFastNodeException.CreateFmt('Fast100: Command "%s" unknown', [typ]);
  175.     end;
  176.   except
  177.     on E: EAbort do
  178.       if tn = nil then
  179.         exit
  180.       else
  181.         raise;
  182.     else
  183.       raise;
  184.   end;
  185. end;
  186.  
  187. end.
  188.