Rev 27 | Rev 31 | 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> . |
||
28 | daniel-mar | 16 | <LeafNode> ::= "N" <Icon(8)> <LineNo(8)> <DescLen(4)> <Desc> . |
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); |
27 | daniel-mar | 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. |