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