Subversion Repositories fastphp

Rev

Rev 31 | Rev 34 | 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
 
33 daniel-mar 21
<Icon(8)>        ::= <Type(4)> <Attr(4)> .
22
 
27 daniel-mar 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;
28 daniel-mar 46
  LEN_ICON    = 8;
27 daniel-mar 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
28 daniel-mar 127
  typ, icon, lineno, len, caption: string;
27 daniel-mar 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
28 daniel-mar 139
        icon   := Read(ptr, LEN_ICON);
27 daniel-mar 140
        lineno := Read(ptr, LEN_LINENO);
28 daniel-mar 141
        len    := Read(ptr, LEN_DESCLEN);
31 daniel-mar 142
        caption := Utf8Decode(Read(ptr, StrToInt(len)));
27 daniel-mar 143
        if tn = nil then
144
          lastTn := Self.Items.Add(nil, caption)
145
        else
146
          lastTn := Self.Items.AddChild(tn, caption);
33 daniel-mar 147
        // lastTn.ImageIndex := // TODO
27 daniel-mar 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
33 daniel-mar 161
      if tn = nil then
162
        exit
163
      else
164
        raise;
27 daniel-mar 165
    else
166
      raise;
167
  end;
168
end;
169
 
170
end.