for TARGET_J2EE only:
[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                 const string onPreRenderScript_1 = @"var {0} = new Object ();\n{0}.treeId = {1};\n{0}.uid = {2};\n{0}.showImage = {3};\n";
1040                 const string onPreRenderScript_2 = @"{0}.form = {1};\n{0}.PopulateNode = function(nodeId) {{ {2}; }};\n{0}.populateFromClient = {3};\n{0}.expandAlt = {4};\n{0}.collapseAlt = {5};\n";
1041                 
1042                 protected internal override void OnPreRender (EventArgs e)
1043                 {
1044                         base.OnPreRender (e);
1045
1046                         if (Page != null) {
1047                                 if (Enabled)
1048                                         Page.RegisterRequiresPostBack (this);
1049                         
1050                                 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1051                                         string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1052                                         Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1053                                 }
1054                         }
1055                         
1056                         string ctree = ClientID + "_data";
1057                         string script = String.Format (onPreRenderScript_1,
1058                                                        ctree,
1059                                                        ClientScriptManager.GetScriptLiteral (ClientID),
1060                                                        ClientScriptManager.GetScriptLiteral (UniqueID),
1061                                                        ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));                      
1062                         
1063                         if (ShowExpandCollapse) {
1064                                 bool defaultImages = ShowLines || ImageSet != TreeViewImageSet.Custom || (ExpandImageUrl == "" && CollapseImageUrl == "");
1065                                 script += String.Concat (ctree, ".defaultImages = ", ClientScriptManager.GetScriptLiteral (defaultImages), ";\n");
1066                                 ImageStyle imageStyle = GetImageStyle ();
1067                                 if (!defaultImages) {
1068                                         script += String.Concat (ctree,
1069                                                                  ".expandImage = ",
1070                                                                  ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)),
1071                                                                  ";\n");
1072                                         script += String.Concat (ctree,
1073                                                                  ".collapseImage = ",
1074                                                                  ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)),
1075                                                                  ";\n");
1076                                 }
1077                                 if (PopulateNodesFromClient)
1078                                         script += String.Concat (ctree,
1079                                                                  ".noExpandImage = ",
1080                                                                  ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)),
1081                                                                  ";\n");
1082                         }
1083
1084                         if (Page != null) {
1085                                 script += String.Format (onPreRenderScript_2,
1086                                                          ctree,
1087                                                          Page.theForm,
1088                                                          Page.ClientScript.GetCallbackEventReference ("this.uid", "nodeId", "TreeView_PopulateCallback",
1089                                                                                                       "this.treeId + \" \" + nodeId",
1090                                                                                                       "TreeView_PopulateCallback", false),
1091                                                          ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient),
1092                                                          ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)),
1093                                                          ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1094
1095                                 if (!Page.IsPostBack) {
1096                                         SetNodesExpandedToDepthRecursive (Nodes);
1097                                 }
1098
1099                                 if (EnableClientScript) {
1100                                         Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1101
1102                                         // Make sure the basic script infrastructure is rendered
1103                                         Page.ClientScript.RegisterWebFormClientScript ();
1104                                 }
1105
1106                                 if (EnableClientScript && PopulateNodesFromClient) {
1107                                         Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1108                                 }
1109
1110                                 EnsureStylesPrepared ();
1111
1112                                 if (hoverNodeStyle != null) {
1113                                         if (Page.Header == null)
1114                                                 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1115                                         RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1116                                         script += String.Concat (ctree, ".hoverClass = ",
1117                                                                  ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass),
1118                                                                  ";\n");
1119                                         script += String.Concat (ctree, ".hoverLinkClass = ",
1120                                                                  ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass),
1121                                                                  ";\n");
1122                                 }
1123                                 
1124                                 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
1125                         }
1126                 }
1127
1128                 void EnsureStylesPrepared () {
1129                         if (stylesPrepared)
1130                                 return;
1131                         stylesPrepared = true;
1132                         PrepareStyles ();
1133                 }
1134
1135                 private void PrepareStyles () {
1136                         // The order in which styles are defined matters when more than one class
1137                         // is assigned to an element
1138                         ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1139                         RegisterStyle (ControlLinkStyle);
1140
1141                         if (nodeStyle != null)
1142                                 RegisterStyle (NodeStyle, NodeLinkStyle);
1143
1144                         if (rootNodeStyle != null)
1145                                 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1146
1147                         if (parentNodeStyle != null)
1148                                 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1149
1150                         if (leafNodeStyle != null)
1151                                 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1152
1153
1154                         if (levelStyles != null && levelStyles.Count > 0) {
1155                                 levelLinkStyles = new List<Style> (levelStyles.Count);
1156                                 foreach (Style style in levelStyles) {
1157                                         Style linkStyle = new Style ();
1158                                         levelLinkStyles.Add (linkStyle);
1159                                         RegisterStyle (style, linkStyle);
1160                                 }
1161                         }
1162
1163                         if (selectedNodeStyle != null)
1164                                 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1165                 }
1166
1167                 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1168                         foreach (TreeNode node in nodes) {
1169                                 if (!node.Expanded.HasValue) {
1170                                         if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1171                                                 node.Expanded = true;
1172                                 }
1173                                 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1174                         }
1175                 }
1176
1177                 string IncrementStyleClassName () {
1178                         registeredStylesCounter++;
1179                         return ClientID + "_" + registeredStylesCounter;
1180                 }
1181
1182                 void RegisterStyle (Style baseStyle, Style linkStyle) {
1183                         linkStyle.CopyTextStylesFrom (baseStyle);
1184                         linkStyle.BorderStyle = BorderStyle.None;
1185                         baseStyle.Font.Reset ();
1186                         RegisterStyle (linkStyle);
1187                         RegisterStyle (baseStyle);
1188                 }
1189
1190                 void RegisterStyle (Style baseStyle) {
1191                         if (Page.Header == null)
1192                                 return;
1193                         string className = IncrementStyleClassName ().Trim ('_');
1194                         baseStyle.SetRegisteredCssClass (className);
1195                         Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1196                 }
1197                 
1198                 string GetBindingKey (string dataMember, int depth)
1199                 {
1200                         return dataMember + " " + depth;
1201                 }
1202                 
1203                 void InitializeDataBindings () {
1204                         if (dataBindings != null && dataBindings.Count > 0) {
1205                                 bindings = new Hashtable ();
1206                                 foreach (TreeNodeBinding bin in dataBindings) {
1207                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
1208                                         bindings [key] = bin;
1209                                 }
1210                         }
1211                         else
1212                                 bindings = null;
1213                 }
1214                 
1215                 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1216                 {
1217                         if (bindings == null)
1218                                 return null;
1219                                 
1220                         TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1221                         if (bin != null) return bin;
1222                         
1223                         bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1224                         if (bin != null) return bin;
1225                         
1226                         bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1227                         if (bin != null) return bin;
1228                         
1229                         return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1230                 }
1231                 
1232                 internal void DecorateNode(TreeNode node)
1233                 {
1234                         if (node == null)
1235                                 return;
1236                         
1237                         if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1238                                 return;
1239
1240                         if (node.IsRootNode && rootNodeStyle != null) {
1241                                 node.ImageUrl = rootNodeStyle.ImageUrl;
1242                                 return;
1243                         }
1244                         if (node.IsParentNode && parentNodeStyle != null) {
1245                                 node.ImageUrl = parentNodeStyle.ImageUrl;
1246                                 return;
1247                         }
1248                         if (node.IsLeafNode && leafNodeStyle != null)
1249                                 node.ImageUrl = leafNodeStyle.ImageUrl;
1250                 }
1251                 
1252                 protected internal override void RenderContents (HtmlTextWriter writer)
1253                 {
1254                         ArrayList levelLines = new ArrayList ();
1255                         int num = Nodes.Count;
1256                         for (int n=0; n<num; n++)
1257                                 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1258                 }
1259                 
1260                 protected override void AddAttributesToRender(HtmlTextWriter writer)
1261                 {
1262                         base.AddAttributesToRender (writer);
1263                 }
1264                 
1265                 public override void RenderBeginTag (HtmlTextWriter writer)
1266                 {
1267                         if (SkipLinkText != "") {
1268                                 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1269                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1270
1271                                 Image img = new Image ();
1272                                 ClientScriptManager csm = new ClientScriptManager (null);
1273                                 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1274                                 img.Attributes.Add ("height", "0");
1275                                 img.Attributes.Add ("width", "0");
1276                                 img.AlternateText = SkipLinkText;
1277                                 img.Render (writer);
1278
1279                                 writer.RenderEndTag ();
1280                         }
1281                         base.RenderBeginTag (writer);
1282                 }
1283                 
1284                 public override void RenderEndTag (HtmlTextWriter writer)
1285                 {
1286                         base.RenderEndTag (writer);
1287
1288                         if (SkipLinkText != "") {
1289                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1290                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1291                                 writer.RenderEndTag ();
1292                         }
1293                 }
1294                 
1295                 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1296                 {
1297                         DecorateNode(node);
1298                         
1299                         string nodeImage;
1300                         bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1301                         ImageStyle imageStyle = GetImageStyle ();
1302                         bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1303                         
1304                         if (clientExpand && !renderChildNodes)
1305                                 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1306                                 
1307                         bool hasChildNodes;
1308                         
1309                         if (renderChildNodes)
1310                                 hasChildNodes = node.ChildNodes.Count > 0;
1311                         else
1312                                 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1313                                 
1314                         writer.AddAttribute ("cellpadding", "0", false);
1315                         writer.AddAttribute ("cellspacing", "0", false);
1316                         writer.AddStyleAttribute ("border-width", "0");
1317                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1318
1319                         Unit nodeSpacing = GetNodeSpacing (node);
1320
1321                         if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1322                                 RenderMenuItemSpacing (writer, nodeSpacing);
1323                         
1324                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1325                         
1326                         // Vertical lines from previous levels
1327
1328                         nodeImage = GetNodeImageUrl ("i", imageStyle);
1329                         for (int n=0; n<level; n++) {
1330                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1331                                 writer.AddStyleAttribute ("width", NodeIndent + "px");
1332                                 writer.AddStyleAttribute ("height", "1px");
1333                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1334                                 if (ShowLines && levelLines [n] != null) {
1335                                         writer.AddAttribute ("src", nodeImage);
1336                                         writer.AddAttribute (HtmlTextWriterAttribute.Alt, "", false);
1337                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1338                                         writer.RenderEndTag ();
1339                                 }
1340                                 writer.RenderEndTag ();
1341                                 writer.RenderEndTag (); // TD
1342                         }
1343                         
1344                         // Node image + line
1345                         
1346                         if (ShowExpandCollapse || ShowLines) {
1347                                 bool buttonImage = false;
1348                                 string tooltip = "";
1349                                 string shape = "";
1350                                 
1351                                 if (ShowLines) {
1352                                         if (hasPrevious && hasNext) shape = "t";
1353                                         else if (hasPrevious && !hasNext) shape = "l";
1354                                         else if (!hasPrevious && hasNext) shape = "r";
1355                                         else shape = "dash";
1356                                 }
1357                                 
1358                                 if (ShowExpandCollapse) {
1359                                         if (hasChildNodes) {
1360                                                 buttonImage = true;
1361                                                 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1362                                                 else shape += "plus";
1363                                                 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1364                                         } else if (!ShowLines)
1365                                                 shape = "noexpand";
1366                                 }
1367
1368                                 if (shape != "") {
1369                                         nodeImage = GetNodeImageUrl (shape, imageStyle);
1370                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1371                                         
1372                                         if (buttonImage) {
1373                                                 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1374                                                         writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1375                                                 else
1376                                                         writer.AddAttribute ("href", GetClientExpandEvent(node));
1377                                                 writer.RenderBeginTag (HtmlTextWriterTag.A);    // Anchor
1378                                         }
1379
1380                                         writer.AddAttribute ("alt", tooltip);
1381
1382                                         if (buttonImage && clientExpand)
1383                                                 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1384                                         writer.AddAttribute ("src", nodeImage);
1385                                         if (buttonImage)
1386                                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1387                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1388                                         writer.RenderEndTag ();
1389                                         
1390                                         if (buttonImage)
1391                                                 writer.RenderEndTag ();         // Anchor
1392
1393                                         writer.RenderEndTag ();         // TD
1394                                 }
1395                         }
1396                         
1397                         // Node icon
1398                         
1399                         string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1400                         if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1401                                 if (imageStyle.RootIcon != null && node.IsRootNode)
1402                                         imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1403                                 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1404                                         imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1405                                 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1406                                         imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1407                         }
1408                         
1409                         if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1410                                 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1411                         
1412                         if (!String.IsNullOrEmpty (imageUrl)) {
1413                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1414                                 BeginNodeTag (writer, node, clientExpand);
1415                                 writer.AddAttribute ("src", imageUrl);
1416                                 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1417                                 writer.AddAttribute ("alt", node.ImageToolTip);
1418                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1419                                 writer.RenderEndTag (); // IMG
1420                                 writer.RenderEndTag (); // style tag
1421                                 writer.RenderEndTag (); // TD
1422                         }
1423
1424                         if (!NodeWrap)
1425                                 writer.AddStyleAttribute ("white-space", "nowrap");
1426                         AddNodeStyle (writer, node, level);
1427                         if (EnableClientScript) {
1428                                 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1429                                 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1430                         }
1431                         writer.RenderBeginTag (HtmlTextWriterTag.Td);   // TD
1432                         
1433                         // Checkbox
1434                         
1435                         if (node.ShowCheckBoxInternal) {
1436                                 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1437                                 writer.AddAttribute ("type", "checkbox", false);
1438                                 writer.AddAttribute ("title", node.Text);
1439                                 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1440                                 writer.RenderBeginTag (HtmlTextWriterTag.Input);        // INPUT
1441                                 writer.RenderEndTag (); // INPUT
1442                         }
1443                         
1444                         // Text
1445                         
1446                         node.BeginRenderText (writer);
1447                         
1448                         if (clientExpand)
1449                                 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1450                         AddNodeLinkStyle (writer, node, level);
1451                         BeginNodeTag (writer, node, clientExpand);
1452                         writer.Write (node.Text);
1453                         writer.RenderEndTag (); // style tag
1454                         
1455                         node.EndRenderText (writer);
1456                         
1457                         writer.RenderEndTag (); // TD
1458                         
1459                         writer.RenderEndTag (); // TR
1460
1461                         if (nodeSpacing != Unit.Empty)
1462                                 RenderMenuItemSpacing (writer, nodeSpacing);
1463                         
1464                         writer.RenderEndTag (); // TABLE
1465                         
1466                         // Children
1467                         
1468                         if (hasChildNodes) {
1469                                 if (level >= levelLines.Count) {
1470                                         if (hasNext)
1471                                                 levelLines.Add (this);
1472                                         else
1473                                                 levelLines.Add (null);
1474                                 } else {
1475                                         if (hasNext)
1476                                                 levelLines [level] = this;
1477                                         else
1478                                                 levelLines [level] = null;
1479                                 }
1480                                 
1481                                 if (clientExpand) {
1482                                         if (!(node.Expanded.HasValue && node.Expanded.Value))
1483                                                 writer.AddStyleAttribute ("display", "none");
1484                                         else
1485                                                 writer.AddStyleAttribute ("display", "block");
1486                                         writer.AddAttribute ("id", GetNodeClientId (node, null));
1487                                         writer.RenderBeginTag (HtmlTextWriterTag.Span);
1488                                         
1489                                         if (renderChildNodes) {
1490                                                 AddChildrenPadding (writer, node);
1491                                                 int num = node.ChildNodes.Count;
1492                                                 for (int n=0; n<num; n++)
1493                                                         RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1494                                                 if (hasNext)
1495                                                         AddChildrenPadding (writer, node);
1496                                         }
1497                                         writer.RenderEndTag (); // SPAN
1498                                 } else if (renderChildNodes) {
1499                                         AddChildrenPadding (writer, node);
1500                                         int num = node.ChildNodes.Count;
1501                                         for (int n=0; n<num; n++)
1502                                                 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1503                                         if (hasNext)
1504                                                 AddChildrenPadding (writer, node);
1505                                 }
1506                         }
1507                 }
1508
1509                 private void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1510                 {
1511                         int level = node.Depth;
1512                         Unit cnp = Unit.Empty;
1513                         
1514                         if (levelStyles != null && level < levelStyles.Count)
1515                                 cnp = levelStyles [level].ChildNodesPadding;
1516                         if (cnp.IsEmpty && nodeStyle != null)
1517                                 cnp = nodeStyle.ChildNodesPadding;
1518                         
1519                         double value;
1520                         if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1521                                 return;
1522
1523                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1524                         writer.AddAttribute ("height", ((int) value).ToString (), false);
1525                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1526                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1527                         writer.RenderEndTag (); // td
1528                         writer.RenderEndTag (); // tr
1529                         writer.RenderEndTag (); // table
1530                 }
1531                 
1532                 private void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1533                         writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1534                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1535                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1536                         writer.RenderEndTag ();
1537                         writer.RenderEndTag ();
1538                 }
1539
1540                 private Unit GetNodeSpacing (TreeNode node) {
1541                         if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1542                                 return selectedNodeStyle.NodeSpacing;
1543                         }
1544
1545                         if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1546                                 return levelStyles [node.Depth].NodeSpacing;
1547                         }
1548
1549                         if (node.IsLeafNode) {
1550                                 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1551                                         return leafNodeStyle.NodeSpacing;
1552                         }
1553                         else if (node.IsRootNode) {
1554                                 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1555                                         return rootNodeStyle.NodeSpacing;
1556                         }
1557                         else if (node.IsParentNode) {
1558                                 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1559                                         return parentNodeStyle.NodeSpacing;
1560                         }
1561
1562                         if (nodeStyle != null)
1563                                 return nodeStyle.NodeSpacing;
1564                         else
1565                                 return Unit.Empty;
1566                 }
1567                 
1568                 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level)
1569                 {
1570                         TreeNodeStyle style = new TreeNodeStyle ();
1571                         if (Page.Header != null) {
1572                                 // styles are registered
1573                                 if (nodeStyle != null) {
1574                                         style.AddCssClass (nodeStyle.CssClass);
1575                                         style.AddCssClass (nodeStyle.RegisteredCssClass);
1576                                 }
1577                                 if (node.IsLeafNode) {
1578                                         if (leafNodeStyle != null) {
1579                                                 style.AddCssClass (leafNodeStyle.CssClass);
1580                                                 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1581                                         }
1582                                 }
1583                                 else if (node.IsRootNode) {
1584                                         if (rootNodeStyle != null) {
1585                                                 style.AddCssClass (rootNodeStyle.CssClass);
1586                                                 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1587                                         }
1588                                 }
1589                                 else if (node.IsParentNode) {
1590                                         if (parentNodeStyle != null) {
1591                                                 style.AddCssClass (parentNodeStyle.CssClass);
1592                                                 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1593                                         }
1594                                 }
1595                                 if (levelStyles != null && levelStyles.Count > level) {
1596                                         style.AddCssClass (levelStyles [level].CssClass);
1597                                         style.AddCssClass (levelStyles [level].RegisteredCssClass);
1598                                 }
1599                                 if (node == SelectedNode && selectedNodeStyle != null) {
1600                                         style.AddCssClass (selectedNodeStyle.CssClass);
1601                                         style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1602                                 }
1603                         }
1604                         else {
1605                                 // styles are not registered
1606                                 if (nodeStyle != null) {
1607                                         style.CopyFrom (nodeStyle);
1608                                 }
1609                                 if (node.IsLeafNode) {
1610                                         if (leafNodeStyle != null) {
1611                                                 style.CopyFrom (leafNodeStyle);
1612                                         }
1613                                 }
1614                                 else if (node.IsRootNode) {
1615                                         if (rootNodeStyle != null) {
1616                                                 style.CopyFrom (rootNodeStyle);
1617                                         }
1618                                 }
1619                                 else if (node.IsParentNode) {
1620                                         if (parentNodeStyle != null) {
1621                                                 style.CopyFrom (parentNodeStyle);
1622                                         }
1623                                 }
1624                                 if (levelStyles != null && levelStyles.Count > level) {
1625                                         style.CopyFrom (levelStyles [level]);
1626                                 }
1627                                 if (node == SelectedNode && selectedNodeStyle != null) {
1628                                         style.CopyFrom (selectedNodeStyle);
1629                                 }
1630                         }
1631                         style.AddAttributesToRender (writer);
1632                 }
1633
1634                 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level) {
1635                         Style style = new Style ();
1636                         if (Page.Header != null) {
1637                                 // styles are registered
1638                                 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1639
1640                                 if (nodeStyle != null) {
1641                                         style.AddCssClass (nodeLinkStyle.CssClass);
1642                                         style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1643                                 }
1644                                 if (node.IsLeafNode) {
1645                                         if (leafNodeStyle != null) {
1646                                                 style.AddCssClass (leafNodeLinkStyle.CssClass);
1647                                                 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1648                                         }
1649                                 }
1650                                 else if (node.IsRootNode) {
1651                                         if (rootNodeStyle != null) {
1652                                                 style.AddCssClass (rootNodeLinkStyle.CssClass);
1653                                                 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1654                                         }
1655                                 }
1656                                 else if (node.IsParentNode) {
1657                                         if (parentNodeStyle != null) {
1658                                                 style.AddCssClass (parentNodeLinkStyle.CssClass);
1659                                                 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1660                                         }
1661                                 }
1662                                 if (levelStyles != null && levelStyles.Count > level) {
1663                                         style.AddCssClass (levelLinkStyles [level].CssClass);
1664                                         style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1665                                 }
1666                                 if (node == SelectedNode && selectedNodeStyle != null) {
1667                                         style.AddCssClass (selectedNodeLinkStyle.CssClass);
1668                                         style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1669                                 }
1670                         }
1671                         else {
1672                                 // styles are not registered
1673                                 style.CopyFrom (ControlLinkStyle);
1674                                 if (nodeStyle != null) {
1675                                         style.CopyFrom (nodeLinkStyle);
1676                                 }
1677                                 if (node.IsLeafNode) {
1678                                         if (node.IsLeafNode && leafNodeStyle != null) {
1679                                                 style.CopyFrom (leafNodeLinkStyle);
1680                                         }
1681                                 }
1682                                 else if (node.IsRootNode) {
1683                                         if (node.IsRootNode && rootNodeStyle != null) {
1684                                                 style.CopyFrom (rootNodeLinkStyle);
1685                                         }
1686                                 }
1687                                 else if (node.IsParentNode) {
1688                                         if (node.IsParentNode && parentNodeStyle != null) {
1689                                                 style.CopyFrom (parentNodeLinkStyle);
1690                                         }
1691                                 }
1692                                 if (levelStyles != null && levelStyles.Count > level) {
1693                                         style.CopyFrom (levelLinkStyles [level]);
1694                                 }
1695                                 if (node == SelectedNode && selectedNodeStyle != null) {
1696                                         style.CopyFrom (selectedNodeLinkStyle);
1697                                 }
1698                                 style.AlwaysRenderTextDecoration = true;
1699                         }
1700                         style.AddAttributesToRender (writer);
1701                 }
1702
1703                 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1704                 {
1705                         if(node.ToolTip.Length>0)
1706                                 writer.AddAttribute ("title", node.ToolTip);
1707
1708                         if (node.NavigateUrl != "") {
1709                                 string target = node.Target.Length > 0 ? node.Target : Target;
1710 #if TARGET_J2EE
1711                                 string navUrl = ResolveClientUrl (node.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1712 #else
1713                                 string navUrl = ResolveClientUrl (node.NavigateUrl);
1714 #endif
1715                                 writer.AddAttribute ("href", navUrl);
1716                                 if (target.Length > 0)
1717                                         writer.AddAttribute ("target", target);
1718                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1719                         }
1720                         else if (node.SelectAction != TreeNodeSelectAction.None) {
1721                                 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1722                                         writer.AddAttribute ("href", GetClientExpandEvent (node));
1723                                 else
1724                                         writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1725                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1726                         }
1727                         else
1728                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1729                 }
1730                 
1731                 string GetNodeImageToolTip (bool expand, string txt) {
1732                         if (expand)  {
1733                                 if (ExpandImageToolTip != "")
1734                                         return String.Format (ExpandImageToolTip, txt);
1735                                 else if (txt != null)
1736                                         return "Expand " + txt;
1737                                 else
1738                                         return "Expand {0}";
1739                         } else {
1740                                 if (CollapseImageToolTip != "")
1741                                         return String.Format (CollapseImageToolTip, txt);
1742                                 else if (txt != null)
1743                                         return "Collapse " + txt;
1744                                 else
1745                                         return "Collapse {0}";
1746                         }
1747                 }
1748                 
1749                 string GetNodeClientId (TreeNode node, string sufix)
1750                 {
1751                         return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1752                 }
1753                                                         
1754                 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1755                 {
1756                         if (ShowLines) {
1757                                 if (!String.IsNullOrEmpty (LineImagesFolder))
1758                                         return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1759                         } else {
1760                                 if (imageStyle != null) {
1761                                         if (shape == "plus") {
1762                                                 if (!String.IsNullOrEmpty (imageStyle.Expand))
1763                                                         return GetNodeIconUrl (imageStyle.Expand);
1764                                         }
1765                                         else if (shape == "minus") {
1766                                                 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1767                                                         return GetNodeIconUrl (imageStyle.Collapse);
1768                                         }
1769                                         else if (shape == "noexpand") {
1770                                                 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1771                                                         return GetNodeIconUrl (imageStyle.NoExpand);
1772                                         }
1773                                 }
1774                                 else {
1775                                         if (shape == "plus") {
1776                                                 if (!String.IsNullOrEmpty (ExpandImageUrl))
1777                                                         return ResolveClientUrl (ExpandImageUrl);
1778                                         }
1779                                         else if (shape == "minus") {
1780                                                 if (!String.IsNullOrEmpty (CollapseImageUrl))
1781                                                         return ResolveClientUrl (CollapseImageUrl);
1782                                         }
1783                                         else if (shape == "noexpand") {
1784                                                 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1785                                                         return ResolveClientUrl (NoExpandImageUrl);
1786                                         }
1787                                 }
1788                                 if (!String.IsNullOrEmpty (LineImagesFolder))
1789                                         return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1790                         }
1791                         return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1792                 }
1793                 
1794                 string GetNodeIconUrl (string icon)
1795                 {
1796                         return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1797                 }
1798                 
1799                 string GetClientEvent (TreeNode node, string ev)
1800                 {
1801                         return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1802                 }
1803                 
1804                 string GetClientExpandEvent (TreeNode node)
1805                 {
1806                         return "javascript:TreeView_ToggleExpand ('" + ClientID + "', '" + node.Path + "')";
1807                 }
1808                 
1809                 TreeNode FindNodeByPos (string path)
1810                 {
1811                         string[] indexes = path.Split ('_');
1812                         TreeNode node = null;
1813                         
1814                         foreach (string index in indexes) {
1815                                 int i = int.Parse (index);
1816                                 if (node == null) {
1817                                         if (i >= Nodes.Count) return null;
1818                                         node = Nodes [i];
1819                                 } else {
1820                                         if (i >= node.ChildNodes.Count) return null;
1821                                         node = node.ChildNodes [i];
1822                                 }
1823                         }
1824                         return node;
1825                 }
1826                 
1827                 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1828                 {
1829                         foreach (TreeNode node in col) {
1830                                 if (node.ShowCheckBoxInternal && node.Checked) {
1831                                         if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1832                                                 node.Checked = false;
1833                                 }
1834                                 if (node.HasChildData)
1835                                         UnsetCheckStates (node.ChildNodes, states);
1836                         }
1837                 }
1838                 
1839                 void SetCheckStates (NameValueCollection states)
1840                 {
1841                         if (states == null)
1842                                 return;
1843
1844                         string keyPrefix = ClientID + "_cs_";
1845                         foreach (string key in states) {
1846                                 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1847                                         string id = key.Substring (keyPrefix.Length);
1848                                         TreeNode node = FindNodeByPos (id);
1849                                         if (node != null && !node.Checked)
1850                                                 node.Checked = true;
1851                                 }
1852                         }
1853                 }
1854                 
1855                 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1856                 {
1857                         foreach (TreeNode node in col) {
1858                                 if (node.Expanded.HasValue && node.Expanded.Value) {
1859                                         bool expand = (Array.IndexOf (states, node.Path) != -1);
1860                                         if (!expand) node.Expanded = false;
1861                                 }
1862                                 if (node.HasChildData)
1863                                         UnsetExpandStates (node.ChildNodes, states);
1864                         }
1865                 }
1866                 
1867                 void SetExpandStates (string[] states)
1868                 {
1869                         foreach (string id in states) {
1870                                 if (id == null || id == "") continue;
1871                                 TreeNode node = FindNodeByPos (id);
1872                                 if (node != null)
1873                                         node.Expanded = true;
1874                         }
1875                 }
1876                 
1877                 string GetExpandStates ()
1878                 {
1879                         StringBuilder sb = new StringBuilder ("|");
1880                         
1881                         foreach (TreeNode node in Nodes)
1882                                 GetExpandStates (sb, node);
1883
1884                         return sb.ToString ();
1885                 }
1886                 
1887                 void GetExpandStates (StringBuilder sb, TreeNode node)
1888                 {
1889                         if (node.Expanded.HasValue && node.Expanded.Value) {
1890                                 sb.Append (node.Path);
1891                                 sb.Append ('|');
1892                         }
1893                         if (node.HasChildData) {
1894                                 foreach (TreeNode child in node.ChildNodes)
1895                                         GetExpandStates (sb, child);
1896                         }
1897                 }
1898         }
1899 }
1900
1901 #endif