2007-12-24 Igor Zelmanovich <igorz@mainsoft.com>
[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 (null, null, null, "warning", "warning", "warning");
116                         imageStyles [TreeViewImageSet.Inbox] = new ImageStyle (null, null, null, "inbox", "inbox", "inbox");
117                         imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
118                         imageStyles [TreeViewImageSet.Simple] = new ImageStyle (null, null, "box_full", null, null, null);
119                         imageStyles [TreeViewImageSet.Simple2] = new ImageStyle (null, null, "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, false);
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                         if (!loading)
765                                 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
766                 }
767                 
768                 internal void NotifyCheckChanged (TreeNode node)
769                 {
770                         OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
771                 }
772
773                 internal void NotifyExpandedChanged (TreeNode node)
774                 {
775                         if (node.Expanded.HasValue && node.Expanded.Value)
776                                 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
777                         else if (node.Expanded.HasValue && node.IsParentNode)
778                                 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
779                 }
780
781                 internal void NotifyPopulateRequired (TreeNode node)
782                 {
783                         OnTreeNodePopulate (new TreeNodeEventArgs (node));
784                 }
785
786                 protected override void TrackViewState()
787                 {
788                         EnsureDataBound ();
789                         
790                         base.TrackViewState();
791                         if (hoverNodeStyle != null) {
792                                 hoverNodeStyle.TrackViewState();
793                         }
794                         if (leafNodeStyle != null) {
795                                 leafNodeStyle.TrackViewState();
796                         }
797                         if (levelStyles != null && levelStyles.Count > 0) {
798                                 ((IStateManager)levelStyles).TrackViewState();
799                         }
800                         if (nodeStyle != null) {
801                                 nodeStyle.TrackViewState();
802                         }
803                         if (parentNodeStyle != null) {
804                                 parentNodeStyle.TrackViewState();
805                         }
806                         if (rootNodeStyle != null) {
807                                 rootNodeStyle.TrackViewState();
808                         }
809                         if (selectedNodeStyle != null) {
810                                 selectedNodeStyle.TrackViewState();
811                         }
812                         if (dataBindings != null) {
813                                 ((IStateManager)dataBindings).TrackViewState ();
814                         }
815                         if (nodes != null) {
816                                 ((IStateManager)nodes).TrackViewState();;
817                         }
818                 }
819
820                 protected override object SaveViewState()
821                 {
822                         object[] states = new object [10];
823                         states[0] = base.SaveViewState();
824                         states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
825                         states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
826                         states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
827                         states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
828                         states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
829                         states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
830                         states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
831                         states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
832                         states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
833
834                         for (int i = states.Length - 1; i >= 0; i--) {
835                                 if (states [i] != null)
836                                         return states;
837                         }
838                         
839                         return null;
840                 }
841
842                 protected override void LoadViewState (object savedState)
843                 {
844                         if (savedState == null)
845                                 return;
846                                 
847                         object [] states = (object []) savedState;
848                         base.LoadViewState (states[0]);
849                         
850                         if (states[1] != null)
851                                 HoverNodeStyle.LoadViewState (states[1]);
852                         if (states[2] != null)
853                                 LeafNodeStyle.LoadViewState(states[2]);
854                         if (states[3] != null)
855                                 ((IStateManager)LevelStyles).LoadViewState(states[3]);
856                         if (states[4] != null)
857                                 NodeStyle.LoadViewState(states[4]);
858                         if (states[5] != null)
859                                 ParentNodeStyle.LoadViewState(states[5]);
860                         if (states[6] != null)
861                                 RootNodeStyle.LoadViewState(states[6]);
862                         if (states[7] != null)
863                                 SelectedNodeStyle.LoadViewState(states[7]);
864                         if (states[8] != null)
865                                 ((IStateManager)DataBindings).LoadViewState(states[8]);
866                         if (states[9] != null)
867                                 ((IStateManager)Nodes).LoadViewState(states[9]);
868                 }
869
870                 protected virtual void RaisePostBackEvent (string eventArgument)
871                 {
872                         string[] args = eventArgument.Split ('|');
873                         TreeNode node = FindNodeByPos (args[1]);
874                         if (node == null) return;
875                         
876                         if (args [0] == "sel")
877                                 HandleSelectEvent (node);
878                         else if (args [0] == "ec")
879                                 HandleExpandCollapseEvent (node);
880                 }
881                 
882                 void HandleSelectEvent (TreeNode node)
883                 {
884                         switch (node.SelectAction) {
885                                 case TreeNodeSelectAction.Select:
886                                         node.Select ();
887                                         break;
888                                 case TreeNodeSelectAction.Expand:
889                                         node.Expand ();
890                                         break;
891                                 case TreeNodeSelectAction.SelectExpand:
892                                         node.Select ();
893                                         node.Expand ();
894                                         break;
895                         }
896                 }
897                 
898                 void HandleExpandCollapseEvent (TreeNode node)
899                 {
900                         node.ToggleExpandState ();
901                 }
902                 
903                 protected virtual void RaisePostDataChangedEvent ()
904                 {
905                 }
906                 
907                 string callbackResult;
908                 protected virtual void RaiseCallbackEvent (string eventArgs)
909                 {
910                         RequiresDataBinding = true;
911                         EnsureDataBound ();
912                         
913                         TreeNode node = FindNodeByPos (eventArgs);
914                         ArrayList levelLines = new ArrayList ();
915                         TreeNode nd = node;
916                         while (nd != null) {
917                                 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
918                                 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
919                                 nd = nd.Parent;
920                         }
921                         
922                         StringWriter sw = new StringWriter ();
923                         HtmlTextWriter writer = new HtmlTextWriter (sw);
924                         EnsureStylesPrepared ();
925                         
926                         node.Expanded = true;
927                         int num = node.ChildNodes.Count;
928                         for (int n=0; n<num; n++)
929                                 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
930                         
931                         string res = sw.ToString ();
932                         callbackResult = res != "" ? res : "*";
933                 }
934                 
935                 protected virtual string GetCallbackResult ()
936                 {
937                         return callbackResult;
938                 }
939
940                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
941                 {
942                         RaisePostBackEvent (eventArgument);
943                 }
944                 
945                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
946                 {
947                         return LoadPostData (postDataKey, postCollection);
948                 }
949                 
950                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
951                 {
952                         RaisePostDataChangedEvent ();
953                 }
954                 
955                 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
956                 {
957                         RaiseCallbackEvent (eventArgs);
958                 }
959                 
960                 string ICallbackEventHandler.GetCallbackResult ()
961                 {
962                         return GetCallbackResult ();
963                 }
964
965                 protected override ControlCollection CreateControlCollection ()
966                 {
967                         return new EmptyControlCollection (this);
968                 }
969                 
970                 protected internal override void PerformDataBinding ()
971                 {
972                         base.PerformDataBinding ();
973                         InitializeDataBindings ();
974                         HierarchicalDataSourceView data = GetData ("");
975                         if (data == null)
976                                 return;
977                         Nodes.Clear ();
978                         IHierarchicalEnumerable e = data.Select ();
979                         FillBoundChildrenRecursive (e, Nodes);
980                 }
981                 
982                 private void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection)
983                 {
984                         if (hEnumerable == null)
985                                 return;
986                         foreach (object obj in hEnumerable) {
987                                 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
988                                 TreeNode child = new TreeNode ();
989                                 nodeCollection.Add (child);
990                                 child.Bind (hdata);
991                                 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
992
993                                 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
994                                         continue;
995
996                                 if (hdata == null || !hdata.HasChildren)
997                                         continue;
998
999                                 IHierarchicalEnumerable e = hdata.GetChildren ();
1000                                 FillBoundChildrenRecursive (e, child.ChildNodes);
1001                         }
1002                 }
1003                 
1004                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1005                 {
1006                         bool res = false;
1007
1008                         if (EnableClientScript && PopulateNodesFromClient) {
1009                                 string states = postCollection [ClientID + "_PopulatedStates"];
1010                                 if (states != null) {
1011                                         foreach (string id in states.Split ('|')) {
1012                                                 if (String.IsNullOrEmpty(id))
1013                                                         continue;
1014                                                 TreeNode node = FindNodeByPos (id);
1015                                                 if (node != null && node.PopulateOnDemand && !node.Populated)
1016                                                         node.Populate();
1017                                         }
1018                                 }
1019                                 res = true;
1020                         }
1021
1022                         UnsetCheckStates (Nodes, postCollection);
1023                         SetCheckStates (postCollection);
1024                         
1025                         if (EnableClientScript) {
1026                                 string states = postCollection [ClientID + "_ExpandStates"];
1027                                 if (states != null) {
1028                                         string[] ids = states.Split ('|');
1029                                         UnsetExpandStates (Nodes, ids);
1030                                         SetExpandStates (ids);
1031                                 }
1032                                 else
1033                                         UnsetExpandStates (Nodes, new string[0]);
1034                                 res = true;
1035                         }
1036                         return res;
1037                 }
1038                 
1039                 protected internal override void OnPreRender (EventArgs e)
1040                 {
1041                         base.OnPreRender (e);
1042
1043                         if (Page != null) {
1044                                 if (Enabled)
1045                                         Page.RegisterRequiresPostBack (this);
1046                         
1047                                 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1048                                         string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1049                                         Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1050                                 }
1051                         }
1052                         
1053                         string ctree = ClientID + "_data";
1054                         string script = string.Format ("var {0} = new Object ();\n", ctree);
1055                         script += string.Format ("{0}.treeId = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ClientID));
1056                         script += string.Format ("{0}.uid = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (UniqueID));
1057                         script += string.Format ("{0}.showImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1058                         
1059                         if (ShowExpandCollapse) {
1060                                 bool defaultImages = ShowLines || ImageSet != TreeViewImageSet.Custom || (ExpandImageUrl == "" && CollapseImageUrl == "");
1061                                 script += string.Format ("{0}.defaultImages = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (defaultImages));
1062                                 ImageStyle imageStyle = GetImageStyle ();
1063                                 if (!defaultImages) {
1064                                         script += string.Format ("{0}.expandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)));
1065                                         script += string.Format ("{0}.collapseImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)));
1066                                 }
1067                                 if (PopulateNodesFromClient)
1068                                         script += string.Format ("{0}.noExpandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)));
1069                         }
1070
1071                         if (Page != null) {
1072                                 script += string.Format ("{0}.form = {1};\n", ctree, Page.theForm);
1073                                 script += string.Format ("{0}.PopulateNode = function(nodeId) {{ {1}; }};\n", ctree, Page.ClientScript.GetCallbackEventReference ("this.uid", "nodeId", "TreeView_PopulateCallback", "this.treeId + \" \" + nodeId", "TreeView_PopulateCallback", false));
1074                                 script += string.Format ("{0}.populateFromClient = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient));
1075                                 script += string.Format ("{0}.expandAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)));
1076                                 script += string.Format ("{0}.collapseAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1077
1078                                 if (!Page.IsPostBack) {
1079                                         SetNodesExpandedToDepthRecursive (Nodes);
1080                                 }
1081
1082                                 if (EnableClientScript) {
1083                                         Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1084
1085                                         // Make sure the basic script infrastructure is rendered
1086                                         Page.ClientScript.RegisterWebFormClientScript ();
1087                                 }
1088
1089                                 if (EnableClientScript && PopulateNodesFromClient) {
1090                                         Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1091                                 }
1092
1093                                 EnsureStylesPrepared ();
1094
1095                                 if (hoverNodeStyle != null) {
1096                                         if (Page.Header == null)
1097                                                 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1098                                         RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1099                                         script += string.Format ("{0}.hoverClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass));
1100                                         script += string.Format ("{0}.hoverLinkClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass));
1101                                 }
1102                                 
1103                                 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
1104                         }
1105                 }
1106
1107                 void EnsureStylesPrepared () {
1108                         if (stylesPrepared)
1109                                 return;
1110                         stylesPrepared = true;
1111                         PrepareStyles ();
1112                 }
1113
1114                 private void PrepareStyles () {
1115                         // The order in which styles are defined matters when more than one class
1116                         // is assigned to an element
1117                         ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1118                         RegisterStyle (ControlLinkStyle);
1119
1120                         if (nodeStyle != null)
1121                                 RegisterStyle (NodeStyle, NodeLinkStyle);
1122
1123                         if (rootNodeStyle != null)
1124                                 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1125
1126                         if (parentNodeStyle != null)
1127                                 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1128
1129                         if (leafNodeStyle != null)
1130                                 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1131
1132
1133                         if (levelStyles != null && levelStyles.Count > 0) {
1134                                 levelLinkStyles = new List<Style> (levelStyles.Count);
1135                                 foreach (Style style in levelStyles) {
1136                                         Style linkStyle = new Style ();
1137                                         levelLinkStyles.Add (linkStyle);
1138                                         RegisterStyle (style, linkStyle);
1139                                 }
1140                         }
1141
1142                         if (selectedNodeStyle != null)
1143                                 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1144                 }
1145
1146                 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1147                         foreach (TreeNode node in nodes) {
1148                                 if (!node.Expanded.HasValue) {
1149                                         if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1150                                                 node.Expanded = true;
1151                                 }
1152                                 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1153                         }
1154                 }
1155
1156                 string IncrementStyleClassName () {
1157                         registeredStylesCounter++;
1158                         return ClientID + "_" + registeredStylesCounter;
1159                 }
1160
1161                 void RegisterStyle (Style baseStyle, Style linkStyle) {
1162                         linkStyle.CopyTextStylesFrom (baseStyle);
1163                         linkStyle.BorderStyle = BorderStyle.None;
1164                         baseStyle.Font.Reset ();
1165                         RegisterStyle (linkStyle);
1166                         RegisterStyle (baseStyle);
1167                 }
1168
1169                 void RegisterStyle (Style baseStyle) {
1170                         if (Page.Header == null)
1171                                 return;
1172                         string className = IncrementStyleClassName ().Trim ('_');
1173                         baseStyle.SetRegisteredCssClass (className);
1174                         Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1175                 }
1176                 
1177                 string GetBindingKey (string dataMember, int depth)
1178                 {
1179                         return dataMember + " " + depth;
1180                 }
1181                 
1182                 void InitializeDataBindings () {
1183                         if (dataBindings != null && dataBindings.Count > 0) {
1184                                 bindings = new Hashtable ();
1185                                 foreach (TreeNodeBinding bin in dataBindings) {
1186                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
1187                                         bindings [key] = bin;
1188                                 }
1189                         }
1190                         else
1191                                 bindings = null;
1192                 }
1193                 
1194                 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1195                 {
1196                         if (bindings == null)
1197                                 return null;
1198                                 
1199                         TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1200                         if (bin != null) return bin;
1201                         
1202                         bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1203                         if (bin != null) return bin;
1204                         
1205                         bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1206                         if (bin != null) return bin;
1207                         
1208                         return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1209                 }
1210                 
1211                 internal void DecorateNode(TreeNode node)
1212                 {
1213                         if (node == null)
1214                                 return;
1215                         
1216                         if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1217                                 return;
1218
1219                         if (node.IsRootNode && rootNodeStyle != null) {
1220                                 node.ImageUrl = rootNodeStyle.ImageUrl;
1221                                 return;
1222                         }
1223                         if (node.IsParentNode && parentNodeStyle != null) {
1224                                 node.ImageUrl = parentNodeStyle.ImageUrl;
1225                                 return;
1226                         }
1227                         if (node.IsLeafNode && leafNodeStyle != null)
1228                                 node.ImageUrl = leafNodeStyle.ImageUrl;
1229                 }
1230                 
1231                 protected internal override void RenderContents (HtmlTextWriter writer)
1232                 {
1233                         ArrayList levelLines = new ArrayList ();
1234                         int num = Nodes.Count;
1235                         for (int n=0; n<num; n++)
1236                                 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1237                 }
1238                 
1239                 protected override void AddAttributesToRender(HtmlTextWriter writer)
1240                 {
1241                         base.AddAttributesToRender (writer);
1242                 }
1243                 
1244                 public override void RenderBeginTag (HtmlTextWriter writer)
1245                 {
1246                         if (SkipLinkText != "") {
1247                                 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1248                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1249
1250                                 Image img = new Image ();
1251                                 ClientScriptManager csm = new ClientScriptManager (null);
1252                                 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1253                                 img.Attributes.Add ("height", "0");
1254                                 img.Attributes.Add ("width", "0");
1255                                 img.AlternateText = SkipLinkText;
1256                                 img.Render (writer);
1257
1258                                 writer.RenderEndTag ();
1259                         }
1260                         base.RenderBeginTag (writer);
1261                 }
1262                 
1263                 public override void RenderEndTag (HtmlTextWriter writer)
1264                 {
1265                         base.RenderEndTag (writer);
1266
1267                         if (SkipLinkText != "") {
1268                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1269                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1270                                 writer.RenderEndTag ();
1271                         }
1272                 }
1273                 
1274                 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1275                 {
1276                         DecorateNode(node);
1277                         
1278                         string nodeImage;
1279                         bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1280                         ImageStyle imageStyle = GetImageStyle ();
1281                         bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1282                         
1283                         if (clientExpand && !renderChildNodes)
1284                                 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1285                                 
1286                         bool hasChildNodes;
1287                         
1288                         if (renderChildNodes)
1289                                 hasChildNodes = node.ChildNodes.Count > 0;
1290                         else
1291                                 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1292                                 
1293                         writer.AddAttribute ("cellpadding", "0", false);
1294                         writer.AddAttribute ("cellspacing", "0", false);
1295                         writer.AddStyleAttribute ("border-width", "0");
1296                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1297
1298                         Unit nodeSpacing = GetNodeSpacing (node);
1299
1300                         if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1301                                 RenderMenuItemSpacing (writer, nodeSpacing);
1302                         
1303                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1304                         
1305                         // Vertical lines from previous levels
1306
1307                         nodeImage = GetNodeImageUrl ("i", imageStyle);
1308                         for (int n=0; n<level; n++) {
1309                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1310                                 writer.AddStyleAttribute ("width", NodeIndent + "px");
1311                                 writer.AddStyleAttribute ("height", "1px");
1312                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1313                                 if (ShowLines && levelLines [n] != null) {
1314                                         writer.AddAttribute ("src", nodeImage);
1315                                         writer.AddAttribute (HtmlTextWriterAttribute.Alt, "", false);
1316                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1317                                         writer.RenderEndTag ();
1318                                 }
1319                                 writer.RenderEndTag ();
1320                                 writer.RenderEndTag (); // TD
1321                         }
1322                         
1323                         // Node image + line
1324                         
1325                         if (ShowExpandCollapse || ShowLines) {
1326                                 bool buttonImage = false;
1327                                 string tooltip = "";
1328                                 string shape = "";
1329                                 
1330                                 if (ShowLines) {
1331                                         if (hasPrevious && hasNext) shape = "t";
1332                                         else if (hasPrevious && !hasNext) shape = "l";
1333                                         else if (!hasPrevious && hasNext) shape = "r";
1334                                         else shape = "dash";
1335                                 }
1336                                 
1337                                 if (ShowExpandCollapse) {
1338                                         if (hasChildNodes) {
1339                                                 buttonImage = true;
1340                                                 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1341                                                 else shape += "plus";
1342                                                 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1343                                         } else if (!ShowLines)
1344                                                 shape = "noexpand";
1345                                 }
1346
1347                                 if (shape != "") {
1348                                         nodeImage = GetNodeImageUrl (shape, imageStyle);
1349                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1350                                         
1351                                         if (buttonImage) {
1352                                                 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1353                                                         writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1354                                                 else
1355                                                         writer.AddAttribute ("href", GetClientExpandEvent(node));
1356                                                 writer.RenderBeginTag (HtmlTextWriterTag.A);    // Anchor
1357                                         }
1358
1359                                         writer.AddAttribute ("alt", tooltip);
1360
1361                                         if (buttonImage && clientExpand)
1362                                                 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1363                                         writer.AddAttribute ("src", nodeImage);
1364                                         if (buttonImage)
1365                                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1366                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1367                                         writer.RenderEndTag ();
1368                                         
1369                                         if (buttonImage)
1370                                                 writer.RenderEndTag ();         // Anchor
1371
1372                                         writer.RenderEndTag ();         // TD
1373                                 }
1374                         }
1375                         
1376                         // Node icon
1377                         
1378                         string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1379                         if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1380                                 if (imageStyle.RootIcon != null && node.IsRootNode)
1381                                         imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1382                                 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1383                                         imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1384                                 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1385                                         imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1386                         }
1387                         
1388                         if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1389                                 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1390                         
1391                         if (!String.IsNullOrEmpty (imageUrl)) {
1392                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1393                                 BeginNodeTag (writer, node, clientExpand);
1394                                 writer.AddAttribute ("src", imageUrl);
1395                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1396                                 writer.AddAttribute ("alt", node.ImageToolTip);
1397                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1398                                 writer.RenderEndTag (); // IMG
1399                                 writer.RenderEndTag (); // style tag
1400                                 writer.RenderEndTag (); // TD
1401                         }
1402
1403                         if (!NodeWrap)
1404                                 writer.AddStyleAttribute ("white-space", "nowrap");
1405                         AddNodeStyle (writer, node, level);
1406                         if (EnableClientScript) {
1407                                 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1408                                 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1409                         }
1410                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1411                         
1412                         // Checkbox
1413                         
1414                         if (node.ShowCheckBoxInternal) {
1415                                 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1416                                 writer.AddAttribute ("type", "checkbox", false);
1417                                 writer.AddAttribute ("title", node.Text);
1418                                 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1419                                 writer.RenderBeginTag (HtmlTextWriterTag.Input);        // INPUT
1420                                 writer.RenderEndTag (); // INPUT
1421                         }
1422                         
1423                         // Text
1424                         
1425                         node.BeginRenderText (writer);
1426                         
1427                         if (clientExpand)
1428                                 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1429                         AddNodeLinkStyle (writer, node, level);
1430                         BeginNodeTag (writer, node, clientExpand);
1431                         writer.Write (node.Text);
1432                         writer.RenderEndTag (); // style tag
1433                         
1434                         node.EndRenderText (writer);
1435                         
1436                         writer.RenderEndTag (); // TD
1437                         
1438                         writer.RenderEndTag (); // TR
1439
1440                         if (nodeSpacing != Unit.Empty)
1441                                 RenderMenuItemSpacing (writer, nodeSpacing);
1442                         
1443                         writer.RenderEndTag (); // TABLE
1444                         
1445                         // Children
1446                         
1447                         if (hasChildNodes) {
1448                                 if (level >= levelLines.Count) {
1449                                         if (hasNext)
1450                                                 levelLines.Add (this);
1451                                         else
1452                                                 levelLines.Add (null);
1453                                 } else {
1454                                         if (hasNext)
1455                                                 levelLines [level] = this;
1456                                         else
1457                                                 levelLines [level] = null;
1458                                 }
1459                                 
1460                                 if (clientExpand) {
1461                                         if (!(node.Expanded.HasValue && node.Expanded.Value))
1462                                                 writer.AddStyleAttribute ("display", "none");
1463                                         else
1464                                                 writer.AddStyleAttribute ("display", "block");
1465                                         writer.AddAttribute ("id", GetNodeClientId (node, null));
1466                                         writer.RenderBeginTag (HtmlTextWriterTag.Span);
1467                                         
1468                                         if (renderChildNodes) {
1469                                                 AddChildrenPadding (writer, node);
1470                                                 int num = node.ChildNodes.Count;
1471                                                 for (int n=0; n<num; n++)
1472                                                         RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1473                                                 if (hasNext)
1474                                                         AddChildrenPadding (writer, node);
1475                                         }
1476                                         writer.RenderEndTag (); // SPAN
1477                                 } else if (renderChildNodes) {
1478                                         AddChildrenPadding (writer, node);
1479                                         int num = node.ChildNodes.Count;
1480                                         for (int n=0; n<num; n++)
1481                                                 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1482                                         if (hasNext)
1483                                                 AddChildrenPadding (writer, node);
1484                                 }
1485                         }
1486                 }
1487
1488                 private void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1489                 {
1490                         int level = node.Depth;
1491                         Unit cnp = Unit.Empty;
1492                         
1493                         if (levelStyles != null && level < levelStyles.Count)
1494                                 cnp = levelStyles [level].ChildNodesPadding;
1495                         if (cnp.IsEmpty && nodeStyle != null)
1496                                 cnp = nodeStyle.ChildNodesPadding;
1497                         
1498                         double value;
1499                         if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1500                                 return;
1501
1502                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1503                         writer.AddAttribute ("height", ((int) value).ToString (), false);
1504                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1505                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1506                         writer.RenderEndTag (); // td
1507                         writer.RenderEndTag (); // tr
1508                         writer.RenderEndTag (); // table
1509                 }
1510                 
1511                 private void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1512                         writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1513                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1514                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1515                         writer.RenderEndTag ();
1516                         writer.RenderEndTag ();
1517                 }
1518
1519                 private Unit GetNodeSpacing (TreeNode node) {
1520                         if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1521                                 return selectedNodeStyle.NodeSpacing;
1522                         }
1523
1524                         if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1525                                 return levelStyles [node.Depth].NodeSpacing;
1526                         }
1527
1528                         if (node.IsLeafNode) {
1529                                 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1530                                         return leafNodeStyle.NodeSpacing;
1531                         }
1532                         else if (node.IsRootNode) {
1533                                 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1534                                         return rootNodeStyle.NodeSpacing;
1535                         }
1536                         else if (node.IsParentNode) {
1537                                 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1538                                         return parentNodeStyle.NodeSpacing;
1539                         }
1540
1541                         if (nodeStyle != null)
1542                                 return nodeStyle.NodeSpacing;
1543                         else
1544                                 return Unit.Empty;
1545                 }
1546                 
1547                 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level)
1548                 {
1549                         TreeNodeStyle style = new TreeNodeStyle ();
1550                         if (Page.Header != null) {
1551                                 // styles are registered
1552                                 if (nodeStyle != null) {
1553                                         style.AddCssClass (nodeStyle.CssClass);
1554                                         style.AddCssClass (nodeStyle.RegisteredCssClass);
1555                                 }
1556                                 if (node.IsLeafNode) {
1557                                         if (leafNodeStyle != null) {
1558                                                 style.AddCssClass (leafNodeStyle.CssClass);
1559                                                 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1560                                         }
1561                                 }
1562                                 else if (node.IsRootNode) {
1563                                         if (rootNodeStyle != null) {
1564                                                 style.AddCssClass (rootNodeStyle.CssClass);
1565                                                 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1566                                         }
1567                                 }
1568                                 else if (node.IsParentNode) {
1569                                         if (parentNodeStyle != null) {
1570                                                 style.AddCssClass (parentNodeStyle.CssClass);
1571                                                 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1572                                         }
1573                                 }
1574                                 if (levelStyles != null && levelStyles.Count > level) {
1575                                         style.AddCssClass (levelStyles [level].CssClass);
1576                                         style.AddCssClass (levelStyles [level].RegisteredCssClass);
1577                                 }
1578                                 if (node == SelectedNode && selectedNodeStyle != null) {
1579                                         style.AddCssClass (selectedNodeStyle.CssClass);
1580                                         style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1581                                 }
1582                         }
1583                         else {
1584                                 // styles are not registered
1585                                 if (nodeStyle != null) {
1586                                         style.CopyFrom (nodeStyle);
1587                                 }
1588                                 if (node.IsLeafNode) {
1589                                         if (leafNodeStyle != null) {
1590                                                 style.CopyFrom (leafNodeStyle);
1591                                         }
1592                                 }
1593                                 else if (node.IsRootNode) {
1594                                         if (rootNodeStyle != null) {
1595                                                 style.CopyFrom (rootNodeStyle);
1596                                         }
1597                                 }
1598                                 else if (node.IsParentNode) {
1599                                         if (parentNodeStyle != null) {
1600                                                 style.CopyFrom (parentNodeStyle);
1601                                         }
1602                                 }
1603                                 if (levelStyles != null && levelStyles.Count > level) {
1604                                         style.CopyFrom (levelStyles [level]);
1605                                 }
1606                                 if (node == SelectedNode && selectedNodeStyle != null) {
1607                                         style.CopyFrom (selectedNodeStyle);
1608                                 }
1609                         }
1610                         style.AddAttributesToRender (writer);
1611                 }
1612
1613                 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level) {
1614                         Style style = new Style ();
1615                         if (Page.Header != null) {
1616                                 // styles are registered
1617                                 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1618
1619                                 if (nodeStyle != null) {
1620                                         style.AddCssClass (nodeLinkStyle.CssClass);
1621                                         style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1622                                 }
1623                                 if (node.IsLeafNode) {
1624                                         if (leafNodeStyle != null) {
1625                                                 style.AddCssClass (leafNodeLinkStyle.CssClass);
1626                                                 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1627                                         }
1628                                 }
1629                                 else if (node.IsRootNode) {
1630                                         if (rootNodeStyle != null) {
1631                                                 style.AddCssClass (rootNodeLinkStyle.CssClass);
1632                                                 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1633                                         }
1634                                 }
1635                                 else if (node.IsParentNode) {
1636                                         if (parentNodeStyle != null) {
1637                                                 style.AddCssClass (parentNodeLinkStyle.CssClass);
1638                                                 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1639                                         }
1640                                 }
1641                                 if (levelStyles != null && levelStyles.Count > level) {
1642                                         style.AddCssClass (levelLinkStyles [level].CssClass);
1643                                         style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1644                                 }
1645                                 if (node == SelectedNode && selectedNodeStyle != null) {
1646                                         style.AddCssClass (selectedNodeLinkStyle.CssClass);
1647                                         style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1648                                 }
1649                         }
1650                         else {
1651                                 // styles are not registered
1652                                 style.CopyFrom (ControlLinkStyle);
1653                                 if (nodeStyle != null) {
1654                                         style.CopyFrom (nodeLinkStyle);
1655                                 }
1656                                 if (node.IsLeafNode) {
1657                                         if (node.IsLeafNode && leafNodeStyle != null) {
1658                                                 style.CopyFrom (leafNodeLinkStyle);
1659                                         }
1660                                 }
1661                                 else if (node.IsRootNode) {
1662                                         if (node.IsRootNode && rootNodeStyle != null) {
1663                                                 style.CopyFrom (rootNodeLinkStyle);
1664                                         }
1665                                 }
1666                                 else if (node.IsParentNode) {
1667                                         if (node.IsParentNode && parentNodeStyle != null) {
1668                                                 style.CopyFrom (parentNodeLinkStyle);
1669                                         }
1670                                 }
1671                                 if (levelStyles != null && levelStyles.Count > level) {
1672                                         style.CopyFrom (levelLinkStyles [level]);
1673                                 }
1674                                 if (node == SelectedNode && selectedNodeStyle != null) {
1675                                         style.CopyFrom (selectedNodeLinkStyle);
1676                                 }
1677                                 style.AlwaysRenderTextDecoration = true;
1678                         }
1679                         style.AddAttributesToRender (writer);
1680                 }
1681
1682                 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1683                 {
1684                         if(node.ToolTip.Length>0)
1685                                 writer.AddAttribute ("title", node.ToolTip);
1686
1687                         if (node.NavigateUrl != "") {
1688                                 string target = node.Target.Length > 0 ? node.Target : Target;
1689 #if TARGET_J2EE
1690                                 string navUrl = ResolveClientUrl (node.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1691 #else
1692                                 string navUrl = ResolveClientUrl (node.NavigateUrl);
1693 #endif
1694                                 writer.AddAttribute ("href", navUrl);
1695                                 if (target.Length > 0)
1696                                         writer.AddAttribute ("target", target);
1697                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1698                         }
1699                         else if (node.SelectAction != TreeNodeSelectAction.None) {
1700                                 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1701                                         writer.AddAttribute ("href", GetClientExpandEvent (node));
1702                                 else
1703                                         writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1704                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1705                         }
1706                         else
1707                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1708                 }
1709                 
1710                 string GetNodeImageToolTip (bool expand, string txt) {
1711                         if (expand)  {
1712                                 if (ExpandImageToolTip != "")
1713                                         return String.Format (ExpandImageToolTip, txt);
1714                                 else if (txt != null)
1715                                         return "Expand " + txt;
1716                                 else
1717                                         return "Expand {0}";
1718                         } else {
1719                                 if (CollapseImageToolTip != "")
1720                                         return String.Format (CollapseImageToolTip, txt);
1721                                 else if (txt != null)
1722                                         return "Collapse " + txt;
1723                                 else
1724                                         return "Collapse {0}";
1725                         }
1726                 }
1727                 
1728                 string GetNodeClientId (TreeNode node, string sufix)
1729                 {
1730                         return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1731                 }
1732                                                         
1733                 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1734                 {
1735                         if (ShowLines) {
1736                                 if (!String.IsNullOrEmpty (LineImagesFolder))
1737                                         return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1738                         } else {
1739                                 if (imageStyle != null) {
1740                                         if (shape == "plus") {
1741                                                 if (!String.IsNullOrEmpty (imageStyle.Expand))
1742                                                         return GetNodeIconUrl (imageStyle.Expand);
1743                                         }
1744                                         else if (shape == "minus") {
1745                                                 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1746                                                         return GetNodeIconUrl (imageStyle.Collapse);
1747                                         }
1748                                         else if (shape == "noexpand") {
1749                                                 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1750                                                         return GetNodeIconUrl (imageStyle.NoExpand);
1751                                         }
1752                                 }
1753                                 else {
1754                                         if (shape == "plus") {
1755                                                 if (!String.IsNullOrEmpty (ExpandImageUrl))
1756                                                         return ResolveClientUrl (ExpandImageUrl);
1757                                         }
1758                                         else if (shape == "minus") {
1759                                                 if (!String.IsNullOrEmpty (CollapseImageUrl))
1760                                                         return ResolveClientUrl (CollapseImageUrl);
1761                                         }
1762                                         else if (shape == "noexpand") {
1763                                                 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1764                                                         return ResolveClientUrl (NoExpandImageUrl);
1765                                         }
1766                                 }
1767                                 if (!String.IsNullOrEmpty (LineImagesFolder))
1768                                         return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1769                         }
1770                         return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1771                 }
1772                 
1773                 string GetNodeIconUrl (string icon)
1774                 {
1775                         return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1776                 }
1777                 
1778                 string GetClientEvent (TreeNode node, string ev)
1779                 {
1780                         return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1781                 }
1782                 
1783                 string GetClientExpandEvent (TreeNode node)
1784                 {
1785                         return "javascript:TreeView_ToggleExpand ('" + ClientID + "', '" + node.Path + "')";
1786                 }
1787                 
1788                 TreeNode FindNodeByPos (string path)
1789                 {
1790                         string[] indexes = path.Split ('_');
1791                         TreeNode node = null;
1792                         
1793                         foreach (string index in indexes) {
1794                                 int i = int.Parse (index);
1795                                 if (node == null) {
1796                                         if (i >= Nodes.Count) return null;
1797                                         node = Nodes [i];
1798                                 } else {
1799                                         if (i >= node.ChildNodes.Count) return null;
1800                                         node = node.ChildNodes [i];
1801                                 }
1802                         }
1803                         return node;
1804                 }
1805                 
1806                 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1807                 {
1808                         foreach (TreeNode node in col) {
1809                                 if (node.ShowCheckBoxInternal && node.Checked) {
1810                                         if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1811                                                 node.Checked = false;
1812                                 }
1813                                 if (node.HasChildData)
1814                                         UnsetCheckStates (node.ChildNodes, states);
1815                         }
1816                 }
1817                 
1818                 void SetCheckStates (NameValueCollection states)
1819                 {
1820                         if (states == null)
1821                                 return;
1822
1823                         string keyPrefix = ClientID + "_cs_";
1824                         foreach (string key in states) {
1825                                 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1826                                         string id = key.Substring (keyPrefix.Length);
1827                                         TreeNode node = FindNodeByPos (id);
1828                                         if (node != null && !node.Checked)
1829                                                 node.Checked = true;
1830                                 }
1831                         }
1832                 }
1833                 
1834                 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1835                 {
1836                         foreach (TreeNode node in col) {
1837                                 if (node.Expanded.HasValue && node.Expanded.Value) {
1838                                         bool expand = (Array.IndexOf (states, node.Path) != -1);
1839                                         if (!expand) node.Expanded = false;
1840                                 }
1841                                 if (node.HasChildData)
1842                                         UnsetExpandStates (node.ChildNodes, states);
1843                         }
1844                 }
1845                 
1846                 void SetExpandStates (string[] states)
1847                 {
1848                         foreach (string id in states) {
1849                                 if (id == null || id == "") continue;
1850                                 TreeNode node = FindNodeByPos (id);
1851                                 if (node != null)
1852                                         node.Expanded = true;
1853                         }
1854                 }
1855                 
1856                 string GetExpandStates ()
1857                 {
1858                         StringBuilder sb = new StringBuilder ("|");
1859                         
1860                         foreach (TreeNode node in Nodes)
1861                                 GetExpandStates (sb, node);
1862
1863                         return sb.ToString ();
1864                 }
1865                 
1866                 void GetExpandStates (StringBuilder sb, TreeNode node)
1867                 {
1868                         if (node.Expanded.HasValue && node.Expanded.Value) {
1869                                 sb.Append (node.Path);
1870                                 sb.Append ('|');
1871                         }
1872                         if (node.HasChildData) {
1873                                 foreach (TreeNode child in node.ChildNodes)
1874                                         GetExpandStates (sb, child);
1875                         }
1876                 }
1877         }
1878 }
1879
1880 #endif