New test.
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / TreeView.cs
1 //
2 // System.Web.UI.WebControls.TreeView.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System.Collections;
34 using System.Text;
35 using System.ComponentModel;
36 using System.Web.Handlers;
37 using System.Collections.Specialized;
38 using System.IO;
39 using System.Security.Permissions;
40 using System.Collections.Generic;
41
42 namespace System.Web.UI.WebControls
43 {
44         // CAS
45         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47         // attributes
48         [SupportsEventValidation]
49         [ControlValueProperty ("SelectedValue")]
50         [DefaultEvent ("SelectedNodeChanged")]
51         [Designer ("System.Web.UI.Design.WebControls.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
52         public class TreeView: HierarchicalDataBoundControl, IPostBackEventHandler, IPostBackDataHandler, ICallbackEventHandler
53         {
54                 bool stylesPrepared;
55                 Style hoverNodeStyle;
56                 TreeNodeStyle leafNodeStyle;
57                 TreeNodeStyle nodeStyle;
58                 TreeNodeStyle parentNodeStyle;
59                 TreeNodeStyle rootNodeStyle;
60                 TreeNodeStyle selectedNodeStyle;
61                 
62                 TreeNodeStyleCollection levelStyles;
63                 TreeNodeCollection nodes;
64                 TreeNodeBindingCollection dataBindings;
65                 
66                 TreeNode selectedNode;
67                 Hashtable bindings;
68
69                 int registeredStylesCounter = -1;
70                 List<Style> levelLinkStyles;
71                 Style controlLinkStyle;
72                 Style nodeLinkStyle;
73                 Style rootNodeLinkStyle;
74                 Style parentNodeLinkStyle;
75                 Style leafNodeLinkStyle;
76                 Style selectedNodeLinkStyle;
77                 Style hoverNodeLinkStyle;
78                 
79                 private static readonly object TreeNodeCheckChangedEvent = new object();
80                 private static readonly object SelectedNodeChangedEvent = new object();
81                 private static readonly object TreeNodeCollapsedEvent = new object();
82                 private static readonly object TreeNodeDataBoundEvent = new object();
83                 private static readonly object TreeNodeExpandedEvent = new object();
84                 private static readonly object TreeNodePopulateEvent = new object();
85                 
86                 static Hashtable imageStyles = new Hashtable ();
87                 
88                 class ImageStyle
89                 {
90                         public ImageStyle (string expand, string collapse, string noExpand, string icon, string iconLeaf, string iconRoot) {
91                                 Expand = expand;
92                                 Collapse = collapse;
93                                 NoExpand = noExpand;
94                                 RootIcon = iconRoot;
95                                 ParentIcon = icon;
96                                 LeafIcon = iconLeaf;
97                         }
98                         
99                         public string Expand;
100                         public string Collapse;
101                         public string NoExpand;
102                         public string RootIcon;
103                         public string ParentIcon;
104                         public string LeafIcon;
105                 }
106                 
107                 static TreeView ()
108                 {
109                         imageStyles [TreeViewImageSet.Arrows] = new ImageStyle ("arrow_plus", "arrow_minus", "arrow_noexpand", null, null, null);
110                         imageStyles [TreeViewImageSet.BulletedList] = new ImageStyle (null, null, null, "dot_full", "dot_empty", "dot_full");
111                         imageStyles [TreeViewImageSet.BulletedList2] = new ImageStyle (null, null, null, "box_full", "box_empty", "box_full");
112                         imageStyles [TreeViewImageSet.BulletedList3] = new ImageStyle (null, null, null, "star_full", "star_empty", "star_full");
113                         imageStyles [TreeViewImageSet.BulletedList4] = new ImageStyle (null, null, null, "star_full", "star_empty", "dots");
114                         imageStyles [TreeViewImageSet.Contacts] = new ImageStyle ("TreeView_plus", "TreeView_minus", "contact", null, null, null);
115                         imageStyles [TreeViewImageSet.Events] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, "warning", null);
116                         imageStyles [TreeViewImageSet.Inbox] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", "inbox", "inbox", "inbox");
117                         imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
118                         imageStyles [TreeViewImageSet.Simple] = new ImageStyle ("TreeView_plus", "TreeView_minus", "box_full", null, null, null);
119                         imageStyles [TreeViewImageSet.Simple2] = new ImageStyle ("TreeView_plus", "TreeView_minus", "box_empty", null, null, null);
120
121                         // TODO
122                         imageStyles [TreeViewImageSet.News] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
123                         imageStyles [TreeViewImageSet.Faq] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
124                         imageStyles [TreeViewImageSet.WindowsHelp] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
125                         imageStyles [TreeViewImageSet.XPFileExplorer] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
126                 }
127                 
128                 public event TreeNodeEventHandler TreeNodeCheckChanged {
129                         add { Events.AddHandler (TreeNodeCheckChangedEvent, value); }
130                         remove { Events.RemoveHandler (TreeNodeCheckChangedEvent, value); }
131                 }
132                 
133                 public event EventHandler SelectedNodeChanged {
134                         add { Events.AddHandler (SelectedNodeChangedEvent, value); }
135                         remove { Events.RemoveHandler (SelectedNodeChangedEvent, value); }
136                 }
137                 
138                 public event TreeNodeEventHandler TreeNodeCollapsed {
139                         add { Events.AddHandler (TreeNodeCollapsedEvent, value); }
140                         remove { Events.RemoveHandler (TreeNodeCollapsedEvent, value); }
141                 }
142                 
143                 public event TreeNodeEventHandler TreeNodeDataBound {
144                         add { Events.AddHandler (TreeNodeDataBoundEvent, value); }
145                         remove { Events.RemoveHandler (TreeNodeDataBoundEvent, value); }
146                 }
147                 
148                 public event TreeNodeEventHandler TreeNodeExpanded {
149                         add { Events.AddHandler (TreeNodeExpandedEvent, value); }
150                         remove { Events.RemoveHandler (TreeNodeExpandedEvent, value); }
151                 }
152                 
153                 public event TreeNodeEventHandler TreeNodePopulate {
154                         add { Events.AddHandler (TreeNodePopulateEvent, value); }
155                         remove { Events.RemoveHandler (TreeNodePopulateEvent, value); }
156                 }
157                 
158                 protected virtual void OnTreeNodeCheckChanged (TreeNodeEventArgs e)
159                 {
160                         if (Events != null) {
161                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCheckChangedEvent];
162                                 if (eh != null) eh (this, e);
163                         }
164                 }
165
166                 protected virtual void OnSelectedNodeChanged (EventArgs e)
167                 {
168                         if (Events != null) {
169                                 EventHandler eh = (EventHandler) Events [SelectedNodeChangedEvent];
170                                 if (eh != null) eh (this, e);
171                         }
172                 }
173
174                 protected virtual void OnTreeNodeCollapsed (TreeNodeEventArgs e)
175                 {
176                         if (Events != null) {
177                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCollapsedEvent];
178                                 if (eh != null) eh (this, e);
179                         }
180                 }
181
182                 protected virtual void OnTreeNodeDataBound (TreeNodeEventArgs e)
183                 {
184                         if (Events != null) {
185                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeDataBoundEvent];
186                                 if (eh != null) eh (this, e);
187                         }
188                 }
189
190                 protected virtual void OnTreeNodeExpanded (TreeNodeEventArgs e)
191                 {
192                         if (Events != null) {
193                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeExpandedEvent];
194                                 if (eh != null) eh (this, e);
195                         }
196                 }
197
198                 protected virtual void OnTreeNodePopulate (TreeNodeEventArgs e)
199                 {
200                         if (Events != null) {
201                                 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodePopulateEvent];
202                                 if (eh != null) eh (this, e);
203                         }
204                 }
205
206
207                 [Localizable (true)]
208                 public string CollapseImageToolTip {
209                         get {
210                                 return ViewState.GetString ("CollapseImageToolTip", "Collapse {0}");
211                         }
212                         set {
213                                 ViewState["CollapseImageToolTip"] = value;
214                         }
215                 }
216
217                 [MonoTODO ("Implement support for this")]
218                 [WebCategory ("Behavior")]
219                 [WebSysDescription ("Whether the tree will automatically generate bindings.")]
220                 [DefaultValue (true)]
221                 public bool AutoGenerateDataBindings {
222                         get {
223                                 return ViewState.GetBool ("AutoGenerateDataBindings", true);
224                         }
225                         set {
226                                 ViewState["AutoGenerateDataBindings"] = value;
227                         }
228                 }
229
230                 [DefaultValue ("")]
231                 [WebSysDescription ("The url of the image to show when a node can be collapsed.")]
232                 [UrlProperty]
233                 [WebCategory ("Appearance")]
234                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
235                 public string CollapseImageUrl {
236                         get {
237                                 return ViewState.GetString ("CollapseImageUrl", "");
238                         }
239                         set {
240                                 ViewState["CollapseImageUrl"] = value;
241                         }
242                 }
243
244                 [WebCategory ("Data")]
245                 [PersistenceMode (PersistenceMode.InnerProperty)]
246                 [WebSysDescription ("Bindings for tree nodes.")]
247                 [Editor ("System.Web.UI.Design.WebControls.TreeViewBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
248                 [DefaultValue (null)]
249                 [MergablePropertyAttribute (false)]
250                 public TreeNodeBindingCollection DataBindings {
251                         get {
252                                 if (dataBindings == null) {
253                                         dataBindings = new TreeNodeBindingCollection ();
254                                         if (IsTrackingViewState)
255                                                 ((IStateManager)dataBindings).TrackViewState();
256                                 }
257                                 return dataBindings;
258                         }
259                 }
260
261                 [WebCategory ("Behavior")]
262                 [WebSysDescription ("Whether the tree view can use client-side script to expand and collapse nodes.")]
263                 [Themeable (false)]
264                 [DefaultValue (true)]
265                 public bool EnableClientScript {
266                         get {
267                                 return ViewState.GetBool ("EnableClientScript", true);
268                         }
269                         set {
270                                 ViewState["EnableClientScript"] = value;
271                         }
272                 }
273
274                 [DefaultValue (-1)]
275                 [WebCategory ("Behavior")]
276                 [WebSysDescription ("The initial expand depth.")]
277                 [TypeConverter ("System.Web.UI.WebControls.TreeView+TreeViewExpandDepthConverter, " + Consts.AssemblySystem_Web)]
278                 public int ExpandDepth {
279                         get {
280                                 return ViewState.GetInt ("ExpandDepth", -1);
281                         }
282                         set {
283                                 ViewState["ExpandDepth"] = value;
284                         }
285                 }
286
287                 [Localizable (true)]
288                 public string ExpandImageToolTip {
289                         get {
290                                 return ViewState.GetString ("ExpandImageToolTip", "Expand {0}");
291                         }
292                         set {
293                                 ViewState["ExpandImageToolTip"] = value;
294                         }
295                 }
296
297                 [DefaultValue ("")]
298                 [UrlProperty]
299                 [WebSysDescription ("The url of the image to show when a node can be expanded.")]
300                 [WebCategory ("Appearance")]
301                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
302                 public string ExpandImageUrl {
303                         get {
304                                 return ViewState.GetString ("ExpandImageUrl", "");
305                         }
306                         set {
307                                 ViewState["ExpandImageUrl"] = value;
308                         }
309                 }
310
311                 [PersistenceMode (PersistenceMode.InnerProperty)]
312                 [NotifyParentProperty (true)]
313                 [DefaultValue (null)]
314                 [WebCategory ("Styles")]
315                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
316                 public Style HoverNodeStyle {
317                         get {
318                                 if (hoverNodeStyle == null) {
319                                         hoverNodeStyle = new Style();
320                                         if (IsTrackingViewState)
321                                                 hoverNodeStyle.TrackViewState();
322                                 }
323                                 return hoverNodeStyle;
324                         }
325                 }
326
327                 [DefaultValue (TreeViewImageSet.Custom)]
328                 public TreeViewImageSet ImageSet {
329                         get {
330                                 return (TreeViewImageSet)ViewState.GetInt ("ImageSet", (int)TreeViewImageSet.Custom);
331                         }
332                         set {
333                                 if (!Enum.IsDefined (typeof (TreeViewImageSet), value))
334                                         throw new ArgumentOutOfRangeException ();
335                                 ViewState["ImageSet"] = value;
336                         }
337                 }
338
339                 [PersistenceMode (PersistenceMode.InnerProperty)]
340                 [NotifyParentProperty (true)]
341                 [DefaultValue (null)]
342                 [WebCategory ("Styles")]
343                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
344                 public TreeNodeStyle LeafNodeStyle {
345                         get {
346                                 if (leafNodeStyle == null) {
347                                         leafNodeStyle = new TreeNodeStyle ();
348                                         if (IsTrackingViewState)
349                                                 leafNodeStyle.TrackViewState();
350                                 }
351                                 return leafNodeStyle;
352                         }
353                 }
354                 
355                 [DefaultValue (null)]
356                 [WebCategory ("Styles")]
357                 [PersistenceMode (PersistenceMode.InnerProperty)]
358                 [Editor ("System.Web.UI.Design.WebControls.TreeNodeStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
359                 public TreeNodeStyleCollection LevelStyles {
360                         get {
361                                 if (levelStyles == null) {
362                                         levelStyles = new TreeNodeStyleCollection ();
363                                         if (IsTrackingViewState)
364                                                 ((IStateManager)levelStyles).TrackViewState();
365                                 }
366                                 return levelStyles;
367                         }
368                 }
369
370                 [DefaultValue ("")]
371                 public string LineImagesFolder {
372                         get {
373                                 return ViewState.GetString ("LineImagesFolder", "");
374                         }
375                         set {
376                                 ViewState["LineImagesFolder"] = value;
377                         }
378                 }
379
380                 [DefaultValue (-1)]
381                 public int MaxDataBindDepth {
382                         get {
383                                 return ViewState.GetInt ("MaxDataBindDepth", -1);
384                         }
385                         set {
386                                 ViewState["MaxDataBindDepth"] = value;
387                         }
388                 }
389
390                 [DefaultValue (20)]
391                 public int NodeIndent {
392                         get {
393                                 return ViewState.GetInt ("NodeIndent", 20);
394                         }
395                         set {
396                                 ViewState["NodeIndent"] = value;
397                         }
398                 }
399                 
400                 [PersistenceMode (PersistenceMode.InnerProperty)]
401                 [Editor ("System.Web.UI.Design.WebControls.TreeNodeCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
402                 [DefaultValueAttribute (null)]
403                 [MergablePropertyAttribute (false)]
404                 public TreeNodeCollection Nodes {
405                         get {
406                                 if (nodes == null) {
407                                         nodes = new TreeNodeCollection (this);
408                                         if (IsTrackingViewState)
409                                                 ((IStateManager)nodes).TrackViewState();
410                                 }
411                                 return nodes;
412                         }
413                 }
414
415                 [PersistenceMode (PersistenceMode.InnerProperty)]
416                 [NotifyParentProperty (true)]
417                 [DefaultValue (null)]
418                 [WebCategory ("Styles")]
419                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
420                 public TreeNodeStyle NodeStyle {
421                         get {
422                                 if (nodeStyle == null) {
423                                         nodeStyle = new TreeNodeStyle ();
424                                         if (IsTrackingViewState)
425                                                 nodeStyle.TrackViewState();
426                                 }
427                                 return nodeStyle;
428                         }
429                 }
430                 
431                 [DefaultValue (false)]
432                 public bool NodeWrap {
433                         get {
434                                 return ViewState.GetBool ("NodeWrap", false);
435                         }
436                         set {
437                                 ViewState ["NodeWrap"] = value;
438                         }
439                 }
440
441                 [UrlProperty]
442                 [DefaultValue ("")]
443                 [WebSysDescription ("The url of the image to show for leaf nodes.")]
444                 [WebCategory ("Appearance")]
445                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
446                 public string NoExpandImageUrl {
447                         get {
448                                 return ViewState.GetString ("NoExpandImageUrl", "");
449                         }
450                         set {
451                                 ViewState ["NoExpandImageUrl"] = value;
452                         }
453                 }
454
455                 [PersistenceMode (PersistenceMode.InnerProperty)]
456                 [NotifyParentProperty (true)]
457                 [DefaultValue (null)]
458                 [WebCategory ("Styles")]
459                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
460                 public TreeNodeStyle ParentNodeStyle {
461                         get {
462                                 if (parentNodeStyle == null) {
463                                         parentNodeStyle = new TreeNodeStyle ();
464                                         if (IsTrackingViewState)
465                                                 parentNodeStyle.TrackViewState();
466                                 }
467                                 return parentNodeStyle;
468                         }
469                 }
470                 
471                 [DefaultValue ('/')]
472                 public char PathSeparator {
473                         get {
474                                 return ViewState.GetChar ("PathSeparator", '/');
475                         }
476                         set {
477                                 ViewState ["PathSeparator"] = value;
478                         }
479                 }
480
481                 [DefaultValue (true)]
482                 public bool PopulateNodesFromClient {
483                         get {
484                                 return ViewState.GetBool ("PopulateNodesFromClient", true);
485                         }
486                         set {
487                                 ViewState ["PopulateNodesFromClient"] = value;
488                         }
489                 }
490
491                 [PersistenceMode (PersistenceMode.InnerProperty)]
492                 [NotifyParentProperty (true)]
493                 [DefaultValue (null)]
494                 [WebCategory ("Styles")]
495                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
496                 public TreeNodeStyle RootNodeStyle {
497                         get {
498                                 if (rootNodeStyle == null) {
499                                         rootNodeStyle = new TreeNodeStyle ();
500                                         if (IsTrackingViewState)
501                                                 rootNodeStyle.TrackViewState();
502                                 }
503                                 return rootNodeStyle;
504                         }
505                 }
506                 
507                 [PersistenceMode (PersistenceMode.InnerProperty)]
508                 [NotifyParentProperty (true)]
509                 [DefaultValue (null)]
510                 [WebCategory ("Styles")]
511                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
512                 public TreeNodeStyle SelectedNodeStyle {
513                         get {
514                                 if (selectedNodeStyle == null) {
515                                         selectedNodeStyle = new TreeNodeStyle ();
516                                         if (IsTrackingViewState)
517                                                 selectedNodeStyle.TrackViewState();
518                                 }
519                                 return selectedNodeStyle;
520                         }
521                 }
522
523                 private Style ControlLinkStyle {
524                         get {
525                                 if (controlLinkStyle == null) {
526                                         controlLinkStyle = new Style ();
527                                         controlLinkStyle.AlwaysRenderTextDecoration = true;
528                                 }
529                                 return controlLinkStyle;
530                         }
531                 }
532
533                 private Style NodeLinkStyle {
534                         get {
535                                 if (nodeLinkStyle == null) {
536                                         nodeLinkStyle = new Style ();
537                                 }
538                                 return nodeLinkStyle;
539                         }
540                 }
541
542                 private Style RootNodeLinkStyle {
543                         get {
544                                 if (rootNodeLinkStyle == null) {
545                                         rootNodeLinkStyle = new Style ();
546                                 }
547                                 return rootNodeLinkStyle;
548                         }
549                 }
550
551                 private Style ParentNodeLinkStyle {
552                         get {
553                                 if (parentNodeLinkStyle == null) {
554                                         parentNodeLinkStyle = new Style ();
555                                 }
556                                 return parentNodeLinkStyle;
557                         }
558                 }
559
560                 private Style SelectedNodeLinkStyle {
561                         get {
562                                 if (selectedNodeLinkStyle == null) {
563                                         selectedNodeLinkStyle = new Style ();
564                                 }
565                                 return selectedNodeLinkStyle;
566                         }
567                 }
568
569                 private Style LeafNodeLinkStyle {
570                         get {
571                                 if (leafNodeLinkStyle == null) {
572                                         leafNodeLinkStyle = new Style ();
573                                 }
574                                 return leafNodeLinkStyle;
575                         }
576                 }
577
578                 private Style HoverNodeLinkStyle {
579                         get {
580                                 if (hoverNodeLinkStyle == null) {
581                                         hoverNodeLinkStyle = new Style ();
582                                 }
583                                 return hoverNodeLinkStyle;
584                         }
585                 }
586                 
587                 [DefaultValue (TreeNodeTypes.None)]
588                 public TreeNodeTypes ShowCheckBoxes {
589                         get {
590                                 return (TreeNodeTypes)ViewState.GetInt ("ShowCheckBoxes", (int)TreeNodeTypes.None);
591                         }
592                         set {
593                                 if ((int) value > 7)
594                                         throw new ArgumentOutOfRangeException ();
595                                 ViewState ["ShowCheckBoxes"] = value;
596                         }
597                 }
598
599                 [DefaultValue (true)]
600                 public bool ShowExpandCollapse {
601                         get {
602                                 return ViewState.GetBool ("ShowExpandCollapse", true);
603                         }
604                         set {
605                                 ViewState ["ShowExpandCollapse"] = value;
606                         }
607                 }
608
609                 [DefaultValue (false)]
610                 public bool ShowLines {
611                         get {
612                                 return ViewState.GetBool ("ShowLines", false);
613                         }
614                         set {
615                                 ViewState ["ShowLines"] = value;
616                         }
617                 }
618
619                 [Localizable (true)]
620                 public string SkipLinkText
621                 {
622                         get {
623                                 return ViewState.GetString ("SkipLinkText", "Skip Navigation Links.");
624                         }
625                         set {
626                                 ViewState ["SkipLinkText"] = value;
627                         }
628                 }
629                 
630                 
631                 [Browsable (false)]
632                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
633                 public TreeNode SelectedNode {
634                         get { return selectedNode; }
635                 }
636
637                 [Browsable (false)]
638                 [DefaultValue ("")]
639                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
640                 public string SelectedValue {
641                         get { return selectedNode != null ? selectedNode.Value : ""; }
642                 }
643
644                 [DefaultValue ("")]
645                 public string Target {
646                         get {
647                                 return ViewState.GetString ("Target", "");
648                         }
649                         set {
650                                 ViewState ["Target"] = value;
651                         }
652                 }
653
654                 [MonoTODO ("why override?")]
655                 public override bool Visible 
656                 {
657                         get {
658                                 return base.Visible;
659                         }
660                         set {
661                                 base.Visible = value;
662                         }
663                 }
664                                 
665                 [Browsable (false)]
666                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
667                 public TreeNodeCollection CheckedNodes {
668                         get {
669                                 TreeNodeCollection col = new TreeNodeCollection ();
670                                 FindCheckedNodes (Nodes, col);
671                                 return col;
672                         }
673                 }
674                 
675                 void FindCheckedNodes (TreeNodeCollection nodeList, TreeNodeCollection result)
676                 {
677                         foreach (TreeNode node in nodeList) {
678                                 if (node.Checked) result.Add (node);
679                                 FindCheckedNodes (node.ChildNodes, result);
680                         }
681                 }
682                 
683                 public void ExpandAll ()
684                 {
685                         foreach (TreeNode node in Nodes)
686                                 node.ExpandAll ();
687                 }
688                 
689                 public void CollapseAll ()
690                 {
691                         foreach (TreeNode node in Nodes)
692                                 node.CollapseAll ();
693                 }
694                 
695                 public TreeNode FindNode (string valuePath)
696                 {
697                         if (valuePath == null) throw new ArgumentNullException ("valuePath");
698                         string[] path = valuePath.Split (PathSeparator);
699                         int n = 0;
700                         TreeNodeCollection col = Nodes;
701                         bool foundBranch = true;
702                         while (col.Count > 0 && foundBranch) {
703                                 foundBranch = false;
704                                 foreach (TreeNode node in col) {
705                                         if (node.Value == path [n]) {
706                                                 if (++n == path.Length) return node;
707                                                 col = node.ChildNodes;
708                                                 foundBranch = true;
709                                                 break;
710                                         }
711                                 }
712                         }
713                         return null;
714                 }
715                 
716                 ImageStyle GetImageStyle ()
717                 {
718                         if (ImageSet != TreeViewImageSet.Custom)
719                                 return (ImageStyle) imageStyles [ImageSet];
720                         else
721                                 return null;
722                 }
723                 
724                 protected override HtmlTextWriterTag TagKey {
725                         get { return HtmlTextWriterTag.Div; }
726                 }
727                 
728                 protected internal virtual TreeNode CreateNode ()
729                 {
730                         return new TreeNode (this);
731                 }
732                 
733                 public sealed override void DataBind ()
734                 {
735                         base.DataBind ();
736                 }
737                 
738                 protected void SetNodeDataBound (TreeNode node, bool dataBound)
739                 {
740                         node.SetDataBound (dataBound);
741                 }
742                 
743                 protected void SetNodeDataPath (TreeNode node, string dataPath)
744                 {
745                         node.SetDataPath (dataPath);
746                 }
747                 
748                 protected void SetNodeDataItem (TreeNode node, object dataItem)
749                 {
750                         node.SetDataItem (dataItem);
751                 }
752                 
753                 protected internal override void OnInit (EventArgs e)
754                 {
755                         base.OnInit (e);
756                 }
757                 
758                 internal void SetSelectedNode (TreeNode node, bool loading)
759                 {
760                         if (selectedNode == node) return;
761                         if (selectedNode != null)
762                                 selectedNode.SelectedFlag = false;
763                         selectedNode = node;
764                         selectedNode.SelectedFlag = true;
765                         if (!loading)
766                                 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
767                 }
768                 
769                 internal void NotifyCheckChanged (TreeNode node)
770                 {
771                         OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
772                 }
773
774                 internal void NotifyExpandedChanged (TreeNode node)
775                 {
776                         if (node.Expanded.HasValue && node.Expanded.Value)
777                                 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
778                         else
779                                 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
780                 }
781
782                 internal void NotifyPopulateRequired (TreeNode node)
783                 {
784                         OnTreeNodePopulate (new TreeNodeEventArgs (node));
785                 }
786
787                 protected override void TrackViewState()
788                 {
789                         EnsureDataBound ();
790                         
791                         base.TrackViewState();
792                         if (hoverNodeStyle != null) {
793                                 hoverNodeStyle.TrackViewState();
794                         }
795                         if (leafNodeStyle != null) {
796                                 leafNodeStyle.TrackViewState();
797                         }
798                         if (levelStyles != null) {
799                                 ((IStateManager)levelStyles).TrackViewState();
800                         }
801                         if (nodeStyle != null) {
802                                 nodeStyle.TrackViewState();
803                         }
804                         if (parentNodeStyle != null) {
805                                 parentNodeStyle.TrackViewState();
806                         }
807                         if (rootNodeStyle != null) {
808                                 rootNodeStyle.TrackViewState();
809                         }
810                         if (selectedNodeStyle != null) {
811                                 selectedNodeStyle.TrackViewState();
812                         }
813                         if (dataBindings != null) {
814                                 ((IStateManager)dataBindings).TrackViewState ();
815                         }
816                         if (nodes != null) {
817                                 ((IStateManager)nodes).TrackViewState();;
818                         }
819                 }
820
821                 protected override object SaveViewState()
822                 {
823                         object[] states = new object [10];
824                         states[0] = base.SaveViewState();
825                         states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
826                         states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
827                         states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
828                         states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
829                         states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
830                         states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
831                         states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
832                         states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
833                         states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
834
835                         for (int i = states.Length - 1; i >= 0; i--) {
836                                 if (states [i] != null)
837                                         return states;
838                         }
839                         
840                         return null;
841                 }
842
843                 protected override void LoadViewState (object savedState)
844                 {
845                         if (savedState == null)
846                                 return;
847                                 
848                         object [] states = (object []) savedState;
849                         base.LoadViewState (states[0]);
850                         
851                         if (states[1] != null)
852                                 HoverNodeStyle.LoadViewState (states[1]);
853                         if (states[2] != null)
854                                 LeafNodeStyle.LoadViewState(states[2]);
855                         if (states[3] != null)
856                                 ((IStateManager)LevelStyles).LoadViewState(states[3]);
857                         if (states[4] != null)
858                                 NodeStyle.LoadViewState(states[4]);
859                         if (states[5] != null)
860                                 ParentNodeStyle.LoadViewState(states[5]);
861                         if (states[6] != null)
862                                 RootNodeStyle.LoadViewState(states[6]);
863                         if (states[7] != null)
864                                 SelectedNodeStyle.LoadViewState(states[7]);
865                         if (states[8] != null)
866                                 ((IStateManager)DataBindings).LoadViewState(states[8]);
867                         if (states[9] != null)
868                                 ((IStateManager)Nodes).LoadViewState(states[9]);
869                 }
870
871                 protected virtual void RaisePostBackEvent (string eventArgument)
872                 {
873                         string[] args = eventArgument.Split ('|');
874                         TreeNode node = FindNodeByPos (args[1]);
875                         if (node == null) return;
876                         
877                         if (args [0] == "sel")
878                                 HandleSelectEvent (node);
879                         else if (args [0] == "ec")
880                                 HandleExpandCollapseEvent (node);
881                 }
882                 
883                 void HandleSelectEvent (TreeNode node)
884                 {
885                         switch (node.SelectAction) {
886                                 case TreeNodeSelectAction.Select:
887                                         node.Select ();
888                                         break;
889                                 case TreeNodeSelectAction.Expand:
890                                         node.Expand ();
891                                         break;
892                                 case TreeNodeSelectAction.SelectExpand:
893                                         node.Select ();
894                                         node.Expand ();
895                                         break;
896                         }
897                 }
898                 
899                 void HandleExpandCollapseEvent (TreeNode node)
900                 {
901                         node.ToggleExpandState ();
902                 }
903                 
904                 protected virtual void RaisePostDataChangedEvent ()
905                 {
906                 }
907                 
908                 string callbackResult;
909                 protected virtual void RaiseCallbackEvent (string eventArgs)
910                 {
911                         RequiresDataBinding = true;
912                         EnsureDataBound ();
913                         
914                         TreeNode node = FindNodeByPos (eventArgs);
915                         ArrayList levelLines = new ArrayList ();
916                         TreeNode nd = node;
917                         while (nd != null) {
918                                 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
919                                 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
920                                 nd = nd.Parent;
921                         }
922                         
923                         StringWriter sw = new StringWriter ();
924                         HtmlTextWriter writer = new HtmlTextWriter (sw);
925                         EnsureStylesPrepared ();
926                         
927                         node.Expanded = true;
928                         int num = node.ChildNodes.Count;
929                         for (int n=0; n<num; n++)
930                                 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
931                         
932                         string res = sw.ToString ();
933                         callbackResult = res != "" ? res : "*";
934                 }
935                 
936                 protected virtual string GetCallbackResult ()
937                 {
938                         return callbackResult;
939                 }
940
941                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
942                 {
943                         RaisePostBackEvent (eventArgument);
944                 }
945                 
946                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
947                 {
948                         return LoadPostData (postDataKey, postCollection);
949                 }
950                 
951                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
952                 {
953                         RaisePostDataChangedEvent ();
954                 }
955                 
956                 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
957                 {
958                         RaiseCallbackEvent (eventArgs);
959                 }
960                 
961                 string ICallbackEventHandler.GetCallbackResult ()
962                 {
963                         return GetCallbackResult ();
964                 }
965
966                 protected override ControlCollection CreateControlCollection ()
967                 {
968                         return new EmptyControlCollection (this);
969                 }
970                 
971                 protected internal override void PerformDataBinding ()
972                 {
973                         base.PerformDataBinding ();
974                         InitializeDataBindings ();
975                         HierarchicalDataSourceView data = GetData ("");
976                         if (data == null)
977                                 return;
978                         Nodes.Clear ();
979                         IHierarchicalEnumerable e = data.Select ();
980                         FillBoundChildrenRecursive (e, Nodes);
981                 }
982                 
983                 private void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection) {
984                         foreach (object obj in hEnumerable) {
985                                 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
986                                 TreeNode child = new TreeNode ();
987                                 nodeCollection.Add (child);
988                                 child.Bind (hdata);
989                                 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
990
991                                 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
992                                         continue;
993
994                                 if (hdata == null || !hdata.HasChildren)
995                                         continue;
996
997                                 IHierarchicalEnumerable e = hdata.GetChildren ();
998                                 FillBoundChildrenRecursive (e, child.ChildNodes);
999                         }
1000                 }
1001                 
1002                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1003                 {
1004                         bool res = false;
1005
1006                         if (EnableClientScript && PopulateNodesFromClient) {
1007                                 string states = postCollection [ClientID + "_PopulatedStates"];
1008                                 if (states != null) {
1009                                         foreach (string id in states.Split ('|')) {
1010                                                 if (String.IsNullOrEmpty(id))
1011                                                         continue;
1012                                                 TreeNode node = FindNodeByPos (id);
1013                                                 if (node != null && node.PopulateOnDemand && !node.Populated)
1014                                                         node.Populate();
1015                                         }
1016                                 }
1017                                 res = true;
1018                         }
1019
1020                         if (ShowCheckBoxes != TreeNodeTypes.None) {
1021                                 UnsetCheckStates (Nodes, postCollection);
1022                                 SetCheckStates (postCollection);
1023                                 res = true;
1024                         }
1025                         
1026                         if (EnableClientScript) {
1027                                 string states = postCollection [ClientID + "_ExpandStates"];
1028                                 if (states != null) {
1029                                         string[] ids = states.Split ('|');
1030                                         UnsetExpandStates (Nodes, ids);
1031                                         SetExpandStates (ids);
1032                                 }
1033                                 else
1034                                         UnsetExpandStates (Nodes, new string[0]);
1035                                 res = true;
1036                         }
1037                         return res;
1038                 }
1039                 
1040                 protected internal override void OnPreRender (EventArgs e)
1041                 {
1042                         base.OnPreRender (e);
1043
1044                         if (Page != null) {
1045                                 if (Enabled)
1046                                         Page.RegisterRequiresPostBack (this);
1047                         
1048                                 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1049                                         string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1050                                         Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1051                                 }
1052                         }
1053                         
1054                         string ctree = ClientID + "_data";
1055                         string script = string.Format ("var {0} = new Object ();\n", ctree);
1056                         script += string.Format ("{0}.showImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1057                         
1058                         if (ShowExpandCollapse) {
1059                                 bool defaultImages = ShowLines || ImageSet != TreeViewImageSet.Custom || (ExpandImageUrl == "" && CollapseImageUrl == "");
1060                                 script += string.Format ("{0}.defaultImages = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (defaultImages));
1061                                 ImageStyle imageStyle = GetImageStyle ();
1062                                 if (!defaultImages) {
1063                                         script += string.Format ("{0}.expandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)));
1064                                         script += string.Format ("{0}.collapseImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)));
1065                                 }
1066                                 if (PopulateNodesFromClient)
1067                                         script += string.Format ("{0}.noExpandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)));
1068                         }
1069
1070                         if (Page != null) {
1071                                 script += string.Format ("{0}.populateFromClient = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient));
1072                                 script += string.Format ("{0}.expandAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)));
1073                                 script += string.Format ("{0}.collapseAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1074
1075                                 if (!Page.IsPostBack) {
1076                                         SetNodesExpandedToDepthRecursive (Nodes);
1077                                 }
1078
1079                                 if (EnableClientScript) {
1080                                         Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1081                                 
1082                                         // Make sure the basic script infrastructure is rendered
1083                                         Page.ClientScript.GetCallbackEventReference (this, "null", "", "null");
1084                                         Page.ClientScript.GetPostBackClientHyperlink (this, "");
1085                                 }
1086
1087                                 if (EnableClientScript && PopulateNodesFromClient) {
1088                                         Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1089                                 }
1090
1091                                 EnsureStylesPrepared ();
1092
1093                                 if (hoverNodeStyle != null) {
1094                                         if (Page.Header == null)
1095                                                 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1096                                         RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1097                                         script += string.Format ("{0}.hoverClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass));
1098                                         script += string.Format ("{0}.hoverLinkClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass));
1099                                 }
1100                                 
1101                                 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
1102                         }
1103                 }
1104
1105                 void EnsureStylesPrepared () {
1106                         if (stylesPrepared)
1107                                 return;
1108                         stylesPrepared = true;
1109                         PrepareStyles ();
1110                 }
1111
1112                 private void PrepareStyles () {
1113                         // The order in which styles are defined matters when more than one class
1114                         // is assigned to an element
1115                         ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1116                         RegisterStyle (ControlLinkStyle);
1117
1118                         if (nodeStyle != null)
1119                                 RegisterStyle (NodeStyle, NodeLinkStyle);
1120
1121                         if (rootNodeStyle != null)
1122                                 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1123
1124                         if (parentNodeStyle != null)
1125                                 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1126
1127                         if (leafNodeStyle != null)
1128                                 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1129
1130
1131                         if (levelStyles != null) {
1132                                 levelLinkStyles = new List<Style> ();
1133                                 foreach (Style style in levelStyles) {
1134                                         Style linkStyle = new Style ();
1135                                         levelLinkStyles.Add (linkStyle);
1136                                         RegisterStyle (style, linkStyle);
1137                                 }
1138                         }
1139
1140                         if (selectedNodeStyle != null)
1141                                 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1142                 }
1143
1144                 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1145                         foreach (TreeNode node in nodes) {
1146                                 if (!node.Expanded.HasValue) {
1147                                         if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1148                                                 node.Expanded = true;
1149                                 }
1150                                 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1151                         }
1152                 }
1153
1154                 string IncrementStyleClassName () {
1155                         registeredStylesCounter++;
1156                         return ClientID + "_" + registeredStylesCounter;
1157                 }
1158
1159                 void RegisterStyle (Style baseStyle, Style linkStyle) {
1160                         linkStyle.CopyTextStylesFrom (baseStyle);
1161                         linkStyle.BorderStyle = BorderStyle.None;
1162                         baseStyle.Font.Reset ();
1163                         RegisterStyle (linkStyle);
1164                         RegisterStyle (baseStyle);
1165                 }
1166
1167                 void RegisterStyle (Style baseStyle) {
1168                         if (Page.Header == null)
1169                                 return;
1170                         string className = IncrementStyleClassName ();
1171                         baseStyle.SetRegisteredCssClass (className);
1172                         Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1173                 }
1174                 
1175                 string GetBindingKey (string dataMember, int depth)
1176                 {
1177                         return dataMember + " " + depth;
1178                 }
1179                 
1180                 void InitializeDataBindings () {
1181                         if (dataBindings != null && dataBindings.Count > 0) {
1182                                 bindings = new Hashtable ();
1183                                 foreach (TreeNodeBinding bin in dataBindings) {
1184                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
1185                                         bindings [key] = bin;
1186                                 }
1187                         }
1188                         else
1189                                 bindings = null;
1190                 }
1191                 
1192                 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1193                 {
1194                         if (bindings == null)
1195                                 return null;
1196                                 
1197                         TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1198                         if (bin != null) return bin;
1199                         
1200                         bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1201                         if (bin != null) return bin;
1202                         
1203                         bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1204                         if (bin != null) return bin;
1205                         
1206                         return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1207                 }
1208                 
1209                 internal void DecorateNode(TreeNode node)
1210                 {
1211                         if (node == null)
1212                                 return;
1213                         
1214                         if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1215                                 return;
1216
1217                         if (node.IsRootNode && rootNodeStyle != null) {
1218                                 node.ImageUrl = rootNodeStyle.ImageUrl;
1219                                 return;
1220                         }
1221                         if (node.IsParentNode && parentNodeStyle != null) {
1222                                 node.ImageUrl = parentNodeStyle.ImageUrl;
1223                                 return;
1224                         }
1225                         if (node.IsLeafNode && leafNodeStyle != null)
1226                                 node.ImageUrl = leafNodeStyle.ImageUrl;
1227                 }
1228                 
1229                 protected internal override void RenderContents (HtmlTextWriter writer)
1230                 {
1231                         ArrayList levelLines = new ArrayList ();
1232                         int num = Nodes.Count;
1233                         for (int n=0; n<num; n++)
1234                                 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1235                 }
1236                 
1237                 protected override void AddAttributesToRender(HtmlTextWriter writer)
1238                 {
1239                         base.AddAttributesToRender (writer);
1240                 }
1241                 
1242                 public override void RenderBeginTag (HtmlTextWriter writer)
1243                 {
1244                         if (SkipLinkText != "") {
1245                                 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1246                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1247
1248                                 Image img = new Image ();
1249                                 ClientScriptManager csm = new ClientScriptManager (null);
1250                                 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1251                                 img.Attributes.Add ("height", "0");
1252                                 img.Attributes.Add ("width", "0");
1253                                 img.AlternateText = SkipLinkText;
1254                                 img.Render (writer);
1255
1256                                 writer.RenderEndTag ();
1257                         }
1258                         base.RenderBeginTag (writer);
1259                 }
1260                 
1261                 public override void RenderEndTag (HtmlTextWriter writer)
1262                 {
1263                         base.RenderEndTag (writer);
1264
1265                         if (SkipLinkText != "") {
1266                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1267                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1268                                 writer.RenderEndTag ();
1269                         }
1270                 }
1271                 
1272                 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1273                 {
1274                         DecorateNode(node);
1275                         
1276                         string nodeImage;
1277                         bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1278                         ImageStyle imageStyle = GetImageStyle ();
1279                         bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1280                         
1281                         if (clientExpand && !renderChildNodes)
1282                                 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1283                                 
1284                         bool hasChildNodes;
1285                         
1286                         if (renderChildNodes)
1287                                 hasChildNodes = node.ChildNodes.Count > 0;
1288                         else
1289                                 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1290                                 
1291                         writer.AddAttribute ("cellpadding", "0");
1292                         writer.AddAttribute ("cellspacing", "0");
1293                         writer.AddStyleAttribute ("border-width", "0");
1294                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1295
1296                         Unit nodeSpacing = GetNodeSpacing (node);
1297
1298                         if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1299                                 RenderMenuItemSpacing (writer, nodeSpacing);
1300                         
1301                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1302                         
1303                         // Vertical lines from previous levels
1304
1305                         nodeImage = GetNodeImageUrl ("i", imageStyle);
1306                         for (int n=0; n<level; n++) {
1307                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1308                                 writer.AddStyleAttribute ("width", NodeIndent + "px");
1309                                 writer.AddStyleAttribute ("height", "1px");
1310                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1311                                 if (ShowLines && levelLines [n] != null) {
1312                                         writer.AddAttribute ("src", nodeImage);
1313                                         writer.AddAttribute (HtmlTextWriterAttribute.Alt, "");
1314                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1315                                         writer.RenderEndTag ();
1316                                 }
1317                                 writer.RenderEndTag ();
1318                                 writer.RenderEndTag (); // TD
1319                         }
1320                         
1321                         // Node image + line
1322                         
1323                         if (ShowExpandCollapse || ShowLines) {
1324                                 bool buttonImage = false;
1325                                 string tooltip = "";
1326                                 string shape = "";
1327                                 
1328                                 if (ShowLines) {
1329                                         if (hasPrevious && hasNext) shape = "t";
1330                                         else if (hasPrevious && !hasNext) shape = "l";
1331                                         else if (!hasPrevious && hasNext) shape = "r";
1332                                         else shape = "dash";
1333                                 }
1334                                 
1335                                 if (ShowExpandCollapse) {
1336                                         if (hasChildNodes) {
1337                                                 buttonImage = true;
1338                                                 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1339                                                 else shape += "plus";
1340                                                 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1341                                         } else if (!ShowLines)
1342                                                 shape = "noexpand";
1343                                 }
1344
1345                                 if (shape != "") {
1346                                         nodeImage = GetNodeImageUrl (shape, imageStyle);
1347                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1348                                         
1349                                         if (buttonImage) {
1350                                                 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1351                                                         writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1352                                                 else
1353                                                         writer.AddAttribute ("href", GetClientExpandEvent(node));
1354                                                 writer.RenderBeginTag (HtmlTextWriterTag.A);    // Anchor
1355                                         }
1356
1357                                         writer.AddAttribute ("alt", tooltip);
1358
1359                                         if (buttonImage && clientExpand)
1360                                                 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1361                                         writer.AddAttribute ("src", nodeImage);
1362                                         if (buttonImage)
1363                                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1364                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1365                                         writer.RenderEndTag ();
1366                                         
1367                                         if (buttonImage)
1368                                                 writer.RenderEndTag ();         // Anchor
1369
1370                                         writer.RenderEndTag ();         // TD
1371                                 }
1372                         }
1373                         
1374                         // Node icon
1375                         
1376                         string imageUrl = node.ImageUrl;
1377                         if (imageUrl == "" && imageStyle != null) {
1378                                 if (imageStyle.RootIcon != null && node.IsRootNode)
1379                                         imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1380                                 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1381                                         imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1382                                 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1383                                         imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1384                         }
1385                         
1386                         if (imageUrl != "") {
1387                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1388                                 BeginNodeTag (writer, node, clientExpand);
1389                                 writer.AddAttribute ("src", imageUrl);
1390                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1391                                 writer.AddAttribute ("alt", node.ImageToolTip);
1392                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1393                                 writer.RenderEndTag (); // IMG
1394                                 writer.RenderEndTag (); // style tag
1395                                 writer.RenderEndTag (); // TD
1396                         }
1397
1398                         if (!NodeWrap)
1399                                 writer.AddStyleAttribute ("white-space", "nowrap");
1400                         AddNodeStyle (writer, node, level);
1401                         if (EnableClientScript) {
1402                                 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)");
1403                                 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1404                         }
1405                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1406                         
1407                         // Checkbox
1408                         
1409                         bool showChecks;
1410                         if (node.ShowCheckBox.HasValue)
1411                                 showChecks = node.ShowCheckBox.Value;
1412                         else
1413                                 showChecks = (ShowCheckBoxes == TreeNodeTypes.All) ||
1414                                                          ((ShowCheckBoxes & TreeNodeTypes.Leaf) > 0 && node.IsLeafNode) ||
1415                                                          ((ShowCheckBoxes & TreeNodeTypes.Parent) > 0 && node.IsParentNode && node.Parent != null) ||
1416                                                          ((ShowCheckBoxes & TreeNodeTypes.Root) > 0 && node.Parent == null && node.ChildNodes.Count > 0);
1417
1418                         if (showChecks) {
1419                                 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1420                                 writer.AddAttribute ("type", "checkbox");
1421                                 writer.AddAttribute ("title", node.Text);
1422                                 if (node.Checked) writer.AddAttribute ("checked", "checked");
1423                                 writer.RenderBeginTag (HtmlTextWriterTag.Input);        // INPUT
1424                                 writer.RenderEndTag (); // INPUT
1425                         }
1426                         
1427                         // Text
1428                         
1429                         node.BeginRenderText (writer);
1430                         
1431                         if (clientExpand)
1432                                 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1433                         AddNodeLinkStyle (writer, node, level);
1434                         BeginNodeTag (writer, node, clientExpand);
1435                         writer.Write (node.Text);
1436                         writer.RenderEndTag (); // style tag
1437                         
1438                         node.EndRenderText (writer);
1439                         
1440                         writer.RenderEndTag (); // TD
1441                         
1442                         writer.RenderEndTag (); // TR
1443
1444                         if (nodeSpacing != Unit.Empty)
1445                                 RenderMenuItemSpacing (writer, nodeSpacing);
1446                         
1447                         writer.RenderEndTag (); // TABLE
1448                         
1449                         // Children
1450                         
1451                         if (hasChildNodes)
1452                         {
1453                                 if (level >= levelLines.Count) {
1454                                         if (hasNext) levelLines.Add (this);
1455                                         else levelLines.Add (null);
1456                                 } else {
1457                                         if (hasNext) levelLines [level] = this;
1458                                         else levelLines [level] = null;
1459                                 }
1460                                 
1461                                 if (clientExpand) {
1462                                         if (!(node.Expanded.HasValue && node.Expanded.Value)) writer.AddStyleAttribute ("display", "none");
1463                                         else writer.AddStyleAttribute ("display", "block");
1464                                         writer.AddAttribute ("id", GetNodeClientId (node, null));
1465                                         writer.RenderBeginTag (HtmlTextWriterTag.Span);
1466                                         
1467                                         if (renderChildNodes) {
1468                                                 int num = node.ChildNodes.Count;
1469                                                 for (int n=0; n<num; n++)
1470                                                         RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1471                                         }
1472                                         writer.RenderEndTag (); // SPAN
1473                                 }
1474                                 else if (renderChildNodes) {
1475                                         int num = node.ChildNodes.Count;
1476                                         for (int n=0; n<num; n++)
1477                                                 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1478                                 }
1479                         }
1480                 }
1481
1482                 private void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1483                         writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1484                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1485                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1486                         writer.RenderEndTag ();
1487                         writer.RenderEndTag ();
1488                 }
1489
1490                 private Unit GetNodeSpacing (TreeNode node) {
1491                         if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1492                                 return selectedNodeStyle.NodeSpacing;
1493                         }
1494
1495                         if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1496                                 return levelStyles [node.Depth].NodeSpacing;
1497                         }
1498
1499                         if (node.IsLeafNode) {
1500                                 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1501                                         return leafNodeStyle.NodeSpacing;
1502                         }
1503                         else if (node.IsRootNode) {
1504                                 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1505                                         return rootNodeStyle.NodeSpacing;
1506                         }
1507                         else if (node.IsParentNode) {
1508                                 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1509                                         return parentNodeStyle.NodeSpacing;
1510                         }
1511
1512                         if (nodeStyle != null)
1513                                 return nodeStyle.NodeSpacing;
1514                         else
1515                                 return Unit.Empty;
1516                 }
1517                 
1518                 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level)
1519                 {
1520                         TreeNodeStyle style = new TreeNodeStyle ();
1521                         if (Page.Header != null) {
1522                                 // styles are registered
1523                                 if (nodeStyle != null) {
1524                                         style.AddCssClass (nodeStyle.CssClass);
1525                                         style.AddCssClass (nodeStyle.RegisteredCssClass);
1526                                 }
1527                                 if (node.IsLeafNode) {
1528                                         if (leafNodeStyle != null) {
1529                                                 style.AddCssClass (leafNodeStyle.CssClass);
1530                                                 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1531                                         }
1532                                 }
1533                                 else if (node.IsRootNode) {
1534                                         if (rootNodeStyle != null) {
1535                                                 style.AddCssClass (rootNodeStyle.CssClass);
1536                                                 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1537                                         }
1538                                 }
1539                                 else if (node.IsParentNode) {
1540                                         if (parentNodeStyle != null) {
1541                                                 style.AddCssClass (parentNodeStyle.CssClass);
1542                                                 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1543                                         }
1544                                 }
1545                                 if (levelStyles != null && levelStyles.Count > level) {
1546                                         style.AddCssClass (levelStyles [level].CssClass);
1547                                         style.AddCssClass (levelStyles [level].RegisteredCssClass);
1548                                 }
1549                                 if (node == SelectedNode && selectedNodeStyle != null) {
1550                                         style.AddCssClass (selectedNodeStyle.CssClass);
1551                                         style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1552                                 }
1553                         }
1554                         else {
1555                                 // styles are not registered
1556                                 if (nodeStyle != null) {
1557                                         style.CopyFrom (nodeStyle);
1558                                 }
1559                                 if (node.IsLeafNode) {
1560                                         if (leafNodeStyle != null) {
1561                                                 style.CopyFrom (leafNodeStyle);
1562                                         }
1563                                 }
1564                                 else if (node.IsRootNode) {
1565                                         if (rootNodeStyle != null) {
1566                                                 style.CopyFrom (rootNodeStyle);
1567                                         }
1568                                 }
1569                                 else if (node.IsParentNode) {
1570                                         if (parentNodeStyle != null) {
1571                                                 style.CopyFrom (parentNodeStyle);
1572                                         }
1573                                 }
1574                                 if (levelStyles != null && levelStyles.Count > level) {
1575                                         style.CopyFrom (levelStyles [level]);
1576                                 }
1577                                 if (node == SelectedNode && selectedNodeStyle != null) {
1578                                         style.CopyFrom (selectedNodeStyle);
1579                                 }
1580                         }
1581                         style.AddAttributesToRender (writer);
1582                 }
1583
1584                 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level) {
1585                         Style style = new Style ();
1586                         if (Page.Header != null) {
1587                                 // styles are registered
1588                                 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1589
1590                                 if (nodeStyle != null) {
1591                                         style.AddCssClass (nodeLinkStyle.CssClass);
1592                                         style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1593                                 }
1594                                 if (node.IsLeafNode) {
1595                                         if (leafNodeStyle != null) {
1596                                                 style.AddCssClass (leafNodeLinkStyle.CssClass);
1597                                                 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1598                                         }
1599                                 }
1600                                 else if (node.IsRootNode) {
1601                                         if (rootNodeStyle != null) {
1602                                                 style.AddCssClass (rootNodeLinkStyle.CssClass);
1603                                                 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1604                                         }
1605                                 }
1606                                 else if (node.IsParentNode) {
1607                                         if (parentNodeStyle != null) {
1608                                                 style.AddCssClass (parentNodeLinkStyle.CssClass);
1609                                                 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1610                                         }
1611                                 }
1612                                 if (levelStyles != null && levelStyles.Count > level) {
1613                                         style.AddCssClass (levelLinkStyles [level].CssClass);
1614                                         style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1615                                 }
1616                                 if (node == SelectedNode && selectedNodeStyle != null) {
1617                                         style.AddCssClass (selectedNodeLinkStyle.CssClass);
1618                                         style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1619                                 }
1620                         }
1621                         else {
1622                                 // styles are not registered
1623                                 style.CopyFrom (ControlLinkStyle);
1624                                 if (nodeStyle != null) {
1625                                         style.CopyFrom (nodeLinkStyle);
1626                                 }
1627                                 if (node.IsLeafNode) {
1628                                         if (node.IsLeafNode && leafNodeStyle != null) {
1629                                                 style.CopyFrom (leafNodeLinkStyle);
1630                                         }
1631                                 }
1632                                 else if (node.IsRootNode) {
1633                                         if (node.IsRootNode && rootNodeStyle != null) {
1634                                                 style.CopyFrom (rootNodeLinkStyle);
1635                                         }
1636                                 }
1637                                 else if (node.IsParentNode) {
1638                                         if (node.IsParentNode && parentNodeStyle != null) {
1639                                                 style.CopyFrom (parentNodeLinkStyle);
1640                                         }
1641                                 }
1642                                 if (levelStyles != null && levelStyles.Count > level) {
1643                                         style.CopyFrom (levelLinkStyles [level]);
1644                                 }
1645                                 if (node == SelectedNode && selectedNodeStyle != null) {
1646                                         style.CopyFrom (selectedNodeLinkStyle);
1647                                 }
1648                                 style.AlwaysRenderTextDecoration = true;
1649                         }
1650                         style.AddAttributesToRender (writer);
1651                 }
1652
1653                 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1654                 {
1655                         if(node.ToolTip.Length>0)
1656                                 writer.AddAttribute ("title", node.ToolTip);
1657
1658                         if (node.NavigateUrl != "") {
1659                                 writer.AddAttribute ("href", node.NavigateUrl);
1660                                 if (node.Target.Length > 0)
1661                                         writer.AddAttribute ("target", node.Target);
1662                                 else if (Target.Length > 0)
1663                                         writer.AddAttribute ("target", Target);
1664                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1665                         }
1666                         else if (node.SelectAction != TreeNodeSelectAction.None) {
1667                                 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1668                                         writer.AddAttribute ("href", GetClientExpandEvent (node));
1669                                 else
1670                                         writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1671                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1672                         }
1673                         else
1674                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1675                 }
1676                 
1677                 string GetNodeImageToolTip (bool expand, string txt) {
1678                         if (expand)  {
1679                                 if (ExpandImageToolTip != "")
1680                                         return String.Format (ExpandImageToolTip, txt);
1681                                 else if (txt != null)
1682                                         return "Expand " + txt;
1683                                 else
1684                                         return "Expand {0}";
1685                         } else {
1686                                 if (CollapseImageToolTip != "")
1687                                         return String.Format (CollapseImageToolTip, txt);
1688                                 else if (txt != null)
1689                                         return "Collapse " + txt;
1690                                 else
1691                                         return "Collapse {0}";
1692                         }
1693                 }
1694                 
1695                 string GetNodeClientId (TreeNode node, string sufix)
1696                 {
1697                         return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1698                 }
1699                                                         
1700                 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1701                 {
1702                         if (ShowLines) {
1703                                 if (LineImagesFolder != "")
1704                                         return LineImagesFolder + "/" + shape + ".gif";
1705                         } else {
1706                                 if (shape == "plus") {
1707                                         if (ExpandImageUrl != "")
1708                                                 return ExpandImageUrl;
1709                                         if (imageStyle != null && imageStyle.Expand != null)
1710                                                 return imageStyle.Expand;
1711                                 }
1712                                 else if (shape == "minus") {
1713                                         if (CollapseImageUrl != "")
1714                                                 return CollapseImageUrl;
1715                                         if (imageStyle != null && imageStyle.Collapse != null)
1716                                                 return imageStyle.Collapse;
1717                                 }
1718                                 else if (shape == "noexpand") {
1719                                         if (NoExpandImageUrl != "")
1720                                                 return NoExpandImageUrl;
1721                                         if (imageStyle != null && imageStyle.NoExpand != null)
1722                                                 return imageStyle.NoExpand;
1723                                 }
1724                         }
1725                         return AssemblyResourceLoader.GetResourceUrl (typeof(TreeView), "TreeView_" + shape + ".gif");
1726                 }
1727                 
1728                 string GetNodeIconUrl (string icon)
1729                 {
1730                         return AssemblyResourceLoader.GetResourceUrl (typeof(TreeView), icon + ".gif");
1731                 }
1732                 
1733                 string GetClientEvent (TreeNode node, string ev)
1734                 {
1735                         return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path);
1736                 }
1737                 
1738                 string GetClientExpandEvent (TreeNode node)
1739                 {
1740                         return "javascript:TreeView_ToggleExpand ('" + ClientID + "', '" + node.Path + "')";
1741                 }
1742                 
1743                 TreeNode FindNodeByPos (string path)
1744                 {
1745                         string[] indexes = path.Split ('_');
1746                         TreeNode node = null;
1747                         
1748                         foreach (string index in indexes) {
1749                                 int i = int.Parse (index);
1750                                 if (node == null) {
1751                                         if (i >= Nodes.Count) return null;
1752                                         node = Nodes [i];
1753                                 } else {
1754                                         if (i >= node.ChildNodes.Count) return null;
1755                                         node = node.ChildNodes [i];
1756                                 }
1757                         }
1758                         return node;
1759                 }
1760                 
1761                 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1762                 {
1763                         foreach (TreeNode node in col) {
1764                                 if (node.Checked) {
1765                                         string val = states [ClientID + "_cs_" + node.Path];
1766                                         if (val != "on") node.Checked = false;
1767                                 }
1768                                 if (node.HasChildData)
1769                                         UnsetCheckStates (node.ChildNodes, states);
1770                         }
1771                 }
1772                 
1773                 void SetCheckStates (NameValueCollection states)
1774                 {
1775                         string keyPrefix = ClientID + "_cs_";
1776                         foreach (string key in states) {
1777                                 if (key.StartsWith (keyPrefix)) {
1778                                         string id = key.Substring (keyPrefix.Length);
1779                                         TreeNode node = FindNodeByPos (id);
1780                                         if (node != null)
1781                                                 node.Checked = (Context.Request.Form [key] == "on");
1782                                 }
1783                         }
1784                 }
1785                 
1786                 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1787                 {
1788                         foreach (TreeNode node in col) {
1789                                 if (node.Expanded.HasValue && node.Expanded.Value) {
1790                                         bool expand = (Array.IndexOf (states, node.Path) != -1);
1791                                         if (!expand) node.Expanded = false;
1792                                 }
1793                                 if (node.HasChildData)
1794                                         UnsetExpandStates (node.ChildNodes, states);
1795                         }
1796                 }
1797                 
1798                 void SetExpandStates (string[] states)
1799                 {
1800                         foreach (string id in states) {
1801                                 if (id == null || id == "") continue;
1802                                 TreeNode node = FindNodeByPos (id);
1803                                 if (node != null)
1804                                         node.Expanded = true;
1805                         }
1806                 }
1807                 
1808                 string GetExpandStates ()
1809                 {
1810                         StringBuilder sb = new StringBuilder ("|");
1811                         
1812                         foreach (TreeNode node in Nodes)
1813                                 GetExpandStates (sb, node);
1814
1815                         return sb.ToString ();
1816                 }
1817                 
1818                 void GetExpandStates (StringBuilder sb, TreeNode node)
1819                 {
1820                         if (node.Expanded.HasValue && node.Expanded.Value) {
1821                                 sb.Append (node.Path);
1822                                 sb.Append ('|');
1823                         }
1824                         if (node.HasChildData) {
1825                                 foreach (TreeNode child in node.ChildNodes)
1826                                         GetExpandStates (sb, child);
1827                         }
1828                 }
1829         }
1830 }
1831
1832 #endif