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. |