Subversion Repositories fastphp

Rev

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