Initial Implementation
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TreeNode.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25 using System;
26 using System.Text;
27 using System.Drawing;
28 using System.Runtime.Serialization;
29
30 namespace System.Windows.Forms {
31
32         [Serializable]
33         public class TreeNode : MarshalByRefObject /*, ICloneable, ISerializable */ {
34
35                 private TreeView tree_view;
36                 internal TreeNode parent;
37                 private int index;
38
39                 private string text;
40                 private int image_index = -1;
41                 private int selected_image_index;
42                 private string full_path;
43                 internal TreeNodeCollection nodes;
44                 
45                 private bool is_expanded = true;
46                 private Rectangle bounds = Rectangle.Empty;
47                 private bool check;
48                 internal OwnerDrawPropertyBag prop_bag;
49
50                 private object tag;
51                 private IntPtr handle;
52                 
53                 internal TreeNode (TreeView tree_view) : this ()
54                 {
55                         this.tree_view = tree_view;
56                 }
57
58                 public TreeNode ()
59                 {
60                         nodes = new TreeNodeCollection (this);
61                 }
62
63                 public TreeNode (string text) : this ()
64                 {
65                         Text = text;
66                 }
67
68                 public TreeNode (string text, TreeNode [] children) : this (text)
69                 {
70                         Nodes.AddRange (children);
71                 }
72
73                 public TreeNode (string text, int image_index, int selected_image_index) : this (text)
74                 {
75                         this.image_index = image_index;
76                         this.selected_image_index = image_index;
77                 }
78
79                 public TreeNode (string text, int image_index, int selected_image_index,
80                                 TreeNode [] children) : this (text, image_index, selected_image_index)
81                 {
82                         Nodes.AddRange (children);
83                 }
84
85                 internal TreeView TreeView {
86                         get {
87                                 if (tree_view != null)
88                                         return tree_view;
89                                 TreeNode walk = parent;
90                                 while (walk != null) {
91                                         if (walk.TreeView != null)
92                                                 tree_view = walk.TreeView;
93                                         walk = walk.parent;
94                                 }
95                                 return tree_view;
96                         }
97                 }
98
99                 public TreeNode Parent {
100                         get {
101                                 if (tree_view != null && tree_view.root_node == parent)
102                                         return null;
103                                 return parent;
104                         }
105                 }
106
107                 public string Text {
108                         get {
109                                 if (text == null)
110                                         return String.Empty;
111                                 return text;
112                         }
113                         set {
114                                 if (text == value)
115                                         return;
116                                 text = value;
117                                 bounds.Width = 0;
118                         }
119                 }
120
121                 public Rectangle Bounds {
122                         get { return bounds; }
123                 }
124
125                 public bool Checked {
126                         get { return check; }
127                         set { check = value; }
128                 }
129
130                 public Color BackColor {
131                         get { return prop_bag.BackColor; }
132                         set { prop_bag.BackColor = value; }
133                 }
134
135                 public Color ForeColor {
136                         get { return prop_bag.ForeColor; }
137                         set { prop_bag.ForeColor = value; }
138                 }
139
140                 public Font NodeFont {
141                         get { return prop_bag.Font; }
142                         set { prop_bag.Font = value; }
143                 }
144
145                 public TreeNodeCollection Nodes {
146                         get {
147                                 if (nodes == null)
148                                         nodes = new TreeNodeCollection (this);
149                                 return nodes;
150                         }
151                 }
152
153                 public TreeNode FirstNode {
154                         get {
155                                 if (nodes.Count > 0)
156                                         return nodes [0];
157                                 return null;
158                         }
159                 }
160
161                 public string FullPath {
162                         get {
163                                 if (full_path != null)
164                                         return full_path;
165
166                                 StringBuilder builder = new StringBuilder ();
167                                 string ps = (TreeView == null ? "/" : TreeView.PathSeparator);
168                                 for (int i = 0; i < nodes.Count; i++) {
169                                         builder.Append (nodes [i].Text);
170                                         if (i - 1 != nodes.Count)
171                                                 builder.Append (ps);
172                                 }
173                                 full_path = builder.ToString ();
174                                 return full_path;
175                         }
176                 }
177
178                 public bool IsExpanded {
179                         get { return is_expanded; }
180                 }
181
182                 public TreeNode NextNode {
183                         get {
184                                 if (parent == null)
185                                         return null;
186                                 if (parent.Nodes.Count > index + 1)
187                                         return parent.Nodes [index + 1];
188                                 return null;
189                         }
190                 }
191                 
192                 public TreeNode PrevNode {
193                         get {
194                                 if (parent == null)
195                                         return null;
196                                 if (index == 0 || index > parent.Nodes.Count)
197                                         return null;
198                                 return parent.Nodes [index - 1];
199                         }
200                 }
201
202                 public TreeNode NextVisibleNode {
203                         get {
204                                 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
205                                 if (!o.MoveNext ())
206                                         return null;
207                                 TreeNode c = (TreeNode) o.Current;
208                                 if (!c.IsInClippingRect)
209                                         return null;
210                                 return c;
211                         }
212                 }
213
214                 public TreeNode PrevVisibleNode {
215                         get {
216                                 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
217                                 if (!o.MovePrevious ())
218                                         return null;
219                                 TreeNode c = (TreeNode) o.Current;
220                                 if (!c.IsInClippingRect)
221                                         return null;
222                                 return c;
223                         }
224                 }
225
226                 public TreeNode LastNode {
227                         get {
228                                 return Nodes [Nodes.Count - 1];
229                         }
230                 }
231
232                 public int Index {
233                         get { return index; }
234                 }
235
236                 public int ImageIndex {
237                         get { return image_index; }
238                         set { image_index = value; }
239                 }
240
241                 public int SelectedImageIndex {
242                         get { return selected_image_index; }
243                         set { selected_image_index = value; }
244                 }
245
246                 public object Tag {
247                         get { return tag; }
248                         set { tag = value; }
249                 }
250
251                 public void Expand ()
252                 {
253                         if (is_expanded)
254                                 return;
255
256                         bool cancel = false;
257                         if (TreeView != null) {
258                                 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
259                                 TreeView.OnBeforeCollapse (e);
260                                 cancel = e.Cancel;
261                         }
262
263                         if (!cancel) {
264                                 is_expanded = true;
265                                 if (TreeView != null)
266                                         TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
267                                 if (IsNodeVisible () && TreeView != null)
268                                         TreeView.UpdateBelow (this);
269                         }
270                 }
271
272                 public void Collapse ()
273                 {
274                         if (!is_expanded)
275                                 return;
276
277                         bool cancel = false;
278                         if (TreeView != null) {
279                                 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
280                                 TreeView.OnBeforeCollapse (e);
281                                 cancel = e.Cancel;
282                         }
283
284                         if (!cancel) {
285                                 is_expanded = false;
286                                 if (TreeView != null)
287                                         TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
288                                 if (IsNodeVisible () && TreeView != null)
289                                         TreeView.UpdateBelow (this);
290                         }
291                 }
292
293                 public void Remove ()
294                 {
295                         if (parent == null)
296                                 return;
297                         parent.Nodes.RemoveAt (Index);
298                 }
299
300                 public void ExpandAll ()
301                 {
302                         ExpandRecursive (this);
303                 }
304
305                 private void ExpandRecursive (TreeNode node)
306                 {
307                         node.Expand ();
308                         foreach (TreeNode child in node.Nodes) {
309                                 ExpandRecursive (child);
310                         }
311                 }
312
313                 internal void CollapseAll ()
314                 {
315                         CollapseRecursive (this);
316                 }
317
318                 private void CollapseRecursive (TreeNode node)
319                 {
320                         node.Collapse ();
321                         foreach (TreeNode child in node.Nodes) {
322                                 CollapseRecursive (child);
323                         }
324                 }
325
326                 public int GetNodeCount (bool include_subtrees)
327                 {
328                         if (!include_subtrees)
329                                 return Nodes.Count;
330
331                         int count = 0;
332                         GetNodeCountRecursive (this, ref count);
333
334                         return count;
335                 }
336
337                 public void Toggle ()
338                 {
339                         if (is_expanded)
340                                 Collapse ();
341                         else
342                                 Expand ();
343
344                         if (TreeView != null)
345                                 TreeView.Refresh ();
346                 }
347
348                 internal void SetNodes (TreeNodeCollection nodes)
349                 {
350                         this.nodes = nodes;
351                 }
352
353                 private void GetNodeCountRecursive (TreeNode node, ref int count)
354                 {
355                         count += node.Nodes.Count;
356                         foreach (TreeNode child in node.Nodes) {
357                                 GetNodeCountRecursive (child, ref count);
358                         }
359                 }
360
361                 public override String ToString ()
362                 {
363                         return String.Concat ("TreeNode: ", Text);
364                 }
365
366                 internal void UpdateBounds (int x, int y, int width, int height)
367                 {
368                         bounds.X = x;
369                         bounds.Y = y;
370                         bounds.Width = width;
371                         bounds.Height = height;
372                 }
373
374                 internal void SetAddedData (TreeView tree_view, TreeNode parent, int index)
375                 {
376                         this.tree_view = tree_view;
377                         this.parent = parent;
378                         this.index = index;
379                 }
380
381                 private bool IsInClippingRect
382                 {
383                         get {
384                                 if (TreeView == null)
385                                         return false;
386                                 if (bounds.Y < 0 && bounds.Y > tree_view.ClientRectangle.Height)
387                                         return false;
388                                 return true;
389                         }
390                 }
391
392                 private bool IsNodeVisible ()
393                 {
394                         if (TreeView == null)
395                                 return false;
396
397                         if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
398                                 return false;
399
400                         TreeNode parent = Parent;
401                         while (parent != null) {
402                                 if (!parent.IsExpanded)
403                                         return false;
404                                 parent = parent.Parent;
405                         }
406                         return true;
407                 }
408         }
409 }
410