Subversion Repositories fastphp

Rev

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

Rev Author Line No. Line
27 daniel-mar 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> .
31 daniel-mar 16
<LeafNode>       ::= "N" <Icon(8)> <LineNo(8)> <DescLen(4)> <Desc(Utf8)> .
27 daniel-mar 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;
28 daniel-mar 44
  LEN_ICON    = 8;
27 daniel-mar 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
28 daniel-mar 125
  typ, icon, lineno, len, caption: string;
27 daniel-mar 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
28 daniel-mar 137
        icon   := Read(ptr, LEN_ICON);
27 daniel-mar 138
        lineno := Read(ptr, LEN_LINENO);
28 daniel-mar 139
        len    := Read(ptr, LEN_DESCLEN);
31 daniel-mar 140
        caption := Utf8Decode(Read(ptr, StrToInt(len)));
27 daniel-mar 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.