2 // System.Web.UI.WebControls.TreeNode.cs
5 // Lluis Sanchez Gual (lluis@novell.com)
7 // (C) 2004 Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
34 using System
.Collections
;
36 using System
.ComponentModel
;
39 namespace System
.Web
.UI
.WebControls
41 [ParseChildrenAttribute (true, "ChildNodes")]
42 public class TreeNode
: IStateManager
, ICloneable
44 StateBag ViewState
= new StateBag ();
45 TreeNodeCollection nodes
;
54 IHierarchyData hierarchyData
;
57 TreeNodeBinding binding
;
58 PropertyDescriptorCollection boundProperties
;
60 bool hadChildrenBeforePopulating
;
62 internal TreeNode (TreeView tree
)
71 public TreeNode (string text
)
76 public TreeNode (string text
, string value)
82 public TreeNode (string text
, string value, string imageUrl
)
89 public TreeNode (string text
, string value, string imageUrl
, string navigateUrl
, string target
)
94 NavigateUrl
= navigateUrl
;
98 [MonoTODO ("Not implemented")]
99 protected TreeNode (TreeView owner
, bool isRoot
)
101 throw new NotImplementedException ();
104 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
108 if (depth
!= -1) return depth
;
110 TreeNode nod
= parent
;
111 while (nod
!= null) {
119 void ResetPathData ()
125 foreach (TreeNode node
in nodes
)
126 node
.ResetPathData ();
130 internal TreeView Tree
{
135 value.SetSelectedNode (this, false);
137 tree
.SetSelectedNode (null, false);
141 nodes
.SetTree (tree
);
143 if (PopulateOnDemand
&& !Populated
&& Expanded
.HasValue
&& Expanded
.Value
)
148 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
149 [DefaultValue (false)]
151 public bool DataBound
{
152 get { return ViewState ["DataBound"] == null ? false : (bool) ViewState ["DataBound"]; }
153 private set { ViewState ["DataBound"] = value; }
156 [DefaultValue (null)]
158 public object DataItem
{
159 get { return dataItem; }
162 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
165 public string DataPath
{
166 get { return ViewState ["DataPath"] == null ? String.Empty : (String) ViewState ["DataPath"]; }
167 private set { ViewState ["DataPath"] = value; }
170 [DefaultValue (false)]
171 public bool Checked
{
173 object o
= ViewState
["Checked"];
174 if (o
!= null) return (bool)o
;
178 ViewState
["Checked"] = value;
180 tree
.NotifyCheckChanged (this);
184 [DefaultValue (null)]
185 [MergableProperty (false)]
187 [PersistenceMode (PersistenceMode
.InnerDefaultProperty
)]
188 public TreeNodeCollection ChildNodes
{
191 nodes
= new TreeNodeCollection (this);
193 if (IsTrackingViewState
)
194 ((IStateManager
)nodes
).TrackViewState();
200 [DefaultValue (null)]
201 public bool? Expanded
{
203 object o
= ViewState
["Expanded"];
207 bool? current
= (bool?) ViewState
["Expanded"];
208 if (current
== value)
210 ViewState
["Expanded"] = value;
212 tree
.NotifyExpandedChanged (this);
213 if (PopulateOnDemand
&& !Populated
&& value.HasValue
&& value.Value
)
220 public string ImageToolTip
{
222 object o
= ViewState
["ImageToolTip"];
227 set { ViewState ["ImageToolTip"] = value; }
232 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts
.AssemblySystem_Design
, typeof (System
.Drawing
.Design
.UITypeEditor
))]
233 public string ImageUrl
{
235 object o
= ViewState
["ImageUrl"];
240 set { ViewState ["ImageUrl"] = value; }
245 [Editor ("System.Web.UI.Design.UrlEditor, " + Consts
.AssemblySystem_Design
, typeof (System
.Drawing
.Design
.UITypeEditor
))]
246 public string NavigateUrl
{
248 object o
= ViewState
["NavigateUrl"];
253 set { ViewState ["NavigateUrl"] = value; }
256 internal bool HadChildrenBeforePopulating
{
257 get { return hadChildrenBeforePopulating; }
262 hadChildrenBeforePopulating
= value;
266 [DefaultValue (false)]
267 public bool PopulateOnDemand
{
269 object o
= ViewState
["PopulateOnDemand"];
275 ViewState
["PopulateOnDemand"] = value;
276 if (value && nodes
!= null && nodes
.Count
> 0)
277 HadChildrenBeforePopulating
= true;
279 HadChildrenBeforePopulating
= false;
283 [DefaultValue (TreeNodeSelectAction
.Select
)]
284 public TreeNodeSelectAction SelectAction
{
286 object o
= ViewState
["SelectAction"];
288 return (TreeNodeSelectAction
)o
;
289 return TreeNodeSelectAction
.Select
;
291 set { ViewState ["SelectAction"] = value; }
294 [DefaultValue (null)]
295 public bool? ShowCheckBox
{
297 object o
= ViewState
["ShowCheckBox"];
300 set { ViewState ["ShowCheckBox"] = value; }
303 internal bool ShowCheckBoxInternal
{
305 if (ShowCheckBox
.HasValue
)
306 return ShowCheckBox
.Value
;
308 return (Tree
.ShowCheckBoxes
== TreeNodeTypes
.All
) ||
309 ((Tree
.ShowCheckBoxes
& TreeNodeTypes
.Leaf
) > 0 && IsLeafNode
) ||
310 ((Tree
.ShowCheckBoxes
& TreeNodeTypes
.Parent
) > 0 && IsParentNode
&& Parent
!= null) ||
311 ((Tree
.ShowCheckBoxes
& TreeNodeTypes
.Root
) > 0 && Parent
== null && ChildNodes
.Count
> 0);
316 public string Target
{
318 object o
= ViewState
["Target"];
323 set { ViewState ["Target"] = value; }
328 [WebSysDescription ("The display text of the tree node.")]
331 object o
= ViewState
["Text"];
333 o
= ViewState
["Value"];
338 set { ViewState ["Text"] = value; }
343 public string ToolTip
{
345 object o
= ViewState
["ToolTip"];
350 set { ViewState ["ToolTip"] = value; }
355 public string Value
{
357 object o
= ViewState
["Value"];
359 o
= ViewState
["Text"];
364 set { ViewState ["Value"] = value; }
367 [DefaultValue (false)]
368 public bool Selected
{
369 get { return SelectedFlag; }
371 SelectedFlag
= value;
374 if (!value && tree
.SelectedNode
== this)
375 tree
.SetSelectedNode (null, false);
377 tree
.SetSelectedNode (this, false);
382 internal virtual bool SelectedFlag
{
384 object o
= ViewState
["Selected"];
389 set { ViewState ["Selected"] = value; }
392 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
394 public TreeNode Parent
{
395 get { return parent; }
398 [DesignerSerializationVisibility (DesignerSerializationVisibility
.Hidden
)]
400 public string ValuePath
{
402 if (tree
== null) return Value
;
404 StringBuilder sb
= new StringBuilder (Value
);
405 TreeNode node
= parent
;
406 while (node
!= null) {
407 sb
.Insert (0, tree
.PathSeparator
);
408 sb
.Insert (0, node
.Value
);
411 return sb
.ToString ();
416 get { return index; }
417 set { index = value; ResetPathData (); }
420 internal void SetParent (TreeNode node
)
426 internal string Path
{
430 StringBuilder sb
= new StringBuilder (index
.ToString());
431 TreeNode node
= parent
;
432 while (node
!= null) {
434 sb
.Insert (0, node
.Index
.ToString ());
437 path
= sb
.ToString ();
442 internal bool Populated
{
444 object o
= ViewState
["Populated"];
449 set { ViewState ["Populated"] = value; }
452 internal bool HasChildData
{
453 get { return nodes != null; }
456 internal void Populate ()
462 tree
.NotifyPopulateRequired (this);
467 public void Collapse ()
472 public void CollapseAll ()
474 SetExpandedRec (false, -1);
477 public void Expand ()
482 internal void Expand (int depth
)
484 SetExpandedRec (true, depth
);
487 public void ExpandAll ()
489 SetExpandedRec (true, -1);
492 void SetExpandedRec (bool expanded
, int depth
)
498 foreach (TreeNode nod
in ChildNodes
)
499 nod
.SetExpandedRec (expanded
, depth
- 1);
502 public void Select ()
507 public void ToggleExpandState ()
509 #if TARGET_JVM //No support for Nullable<bool>.GetValueOrDefault() yet
510 bool? value = Expanded
;
511 Expanded
= value.HasValue
? !value.Value
: true;
513 Expanded
= !Expanded
.GetValueOrDefault(false);
517 void IStateManager
.LoadViewState (object savedState
)
519 LoadViewState (savedState
);
522 protected virtual void LoadViewState (object savedState
)
524 if (savedState
== null)
527 object[] states
= (object[]) savedState
;
528 ViewState
.LoadViewState (states
[0]);
530 if (tree
!= null && SelectedFlag
)
531 tree
.SetSelectedNode (this, true);
533 if (!PopulateOnDemand
|| Populated
)
534 ((IStateManager
)ChildNodes
).LoadViewState (states
[1]);
537 object IStateManager
.SaveViewState ()
539 return SaveViewState ();
542 protected virtual object SaveViewState ()
544 object[] states
= new object[2];
545 states
[0] = ViewState
.SaveViewState();
546 states
[1] = (nodes
== null ? null : ((IStateManager
)nodes
).SaveViewState());
548 for (int i
= 0; i
< states
.Length
; i
++) {
549 if (states
[i
] != null)
555 void IStateManager
.TrackViewState ()
560 protected void TrackViewState ()
564 ViewState
.TrackViewState();
567 ((IStateManager
)nodes
).TrackViewState ();
570 bool IStateManager
.IsTrackingViewState
{
571 get { return IsTrackingViewState; }
574 protected bool IsTrackingViewState
{
575 get { return marked; }
578 internal void SetDirty ()
580 ViewState
.SetDirty (true);
585 public virtual object Clone ()
587 TreeNode nod
= tree
!= null ? tree
.CreateNode () : new TreeNode ();
588 foreach (DictionaryEntry e
in ViewState
)
589 nod
.ViewState
[(string)e
.Key
] = ((StateItem
)e
.Value
).Value
;
591 foreach (TreeNode c
in ChildNodes
)
592 nod
.ChildNodes
.Add ((TreeNode
)c
.Clone ());
597 object ICloneable
.Clone ()
602 internal void Bind (IHierarchyData hierarchyData
)
604 this.hierarchyData
= hierarchyData
;
606 DataPath
= hierarchyData
.Path
;
607 dataItem
= hierarchyData
.Item
;
609 TreeNodeBinding bin
= GetBinding ();
612 // Bind ImageToolTip property
614 if (bin
.ImageToolTipField
.Length
> 0) {
615 ImageToolTip
= Convert
.ToString (GetBoundPropertyValue (bin
.ImageToolTipField
));
616 if (ImageToolTip
.Length
== 0)
617 ImageToolTip
= bin
.ImageToolTip
;
618 } else if (bin
.ImageToolTip
.Length
> 0)
619 ImageToolTip
= bin
.ImageToolTip
;
621 // Bind ImageUrl property
623 if (bin
.ImageUrlField
.Length
> 0) {
624 ImageUrl
= Convert
.ToString (GetBoundPropertyValue (bin
.ImageUrlField
));
625 if (ImageUrl
.Length
== 0)
626 ImageUrl
= bin
.ImageUrl
;
627 } else if (bin
.ImageUrl
.Length
> 0)
628 ImageUrl
= bin
.ImageUrl
;
630 // Bind NavigateUrl property
632 if (bin
.NavigateUrlField
.Length
> 0) {
633 NavigateUrl
= Convert
.ToString (GetBoundPropertyValue (bin
.NavigateUrlField
));
634 if (NavigateUrl
.Length
== 0)
635 NavigateUrl
= bin
.NavigateUrl
;
636 } else if (bin
.NavigateUrl
.Length
> 0)
637 NavigateUrl
= bin
.NavigateUrl
;
639 // Bind PopulateOnDemand property
641 if (bin
.HasPropertyValue ("PopulateOnDemand"))
642 PopulateOnDemand
= bin
.PopulateOnDemand
;
644 // Bind SelectAction property
646 if (bin
.HasPropertyValue ("SelectAction"))
647 SelectAction
= bin
.SelectAction
;
649 // Bind ShowCheckBox property
651 if (bin
.HasPropertyValue ("ShowCheckBox"))
652 ShowCheckBox
= bin
.ShowCheckBox
;
654 // Bind Target property
656 if (bin
.TargetField
.Length
> 0) {
657 Target
= Convert
.ToString (GetBoundPropertyValue (bin
.TargetField
));
658 if (Target
.Length
== 0)
660 } else if (bin
.Target
.Length
> 0)
663 // Bind Text property
665 if (bin
.TextField
.Length
> 0) {
666 text
= Convert
.ToString (GetBoundPropertyValue (bin
.TextField
));
667 if (bin
.FormatString
.Length
> 0)
668 text
= string.Format (bin
.FormatString
, text
);
670 if (String
.IsNullOrEmpty (text
)) {
671 if (bin
.Text
.Length
> 0)
673 else if (bin
.Value
.Length
> 0)
676 if (!String
.IsNullOrEmpty (text
))
679 // Bind ToolTip property
681 if (bin
.ToolTipField
.Length
> 0) {
682 ToolTip
= Convert
.ToString (GetBoundPropertyValue (bin
.ToolTipField
));
683 if (ToolTip
.Length
== 0)
684 ToolTip
= bin
.ToolTip
;
685 } else if (bin
.ToolTip
.Length
> 0)
686 ToolTip
= bin
.ToolTip
;
688 // Bind Value property
690 if (bin
.ValueField
.Length
> 0) {
691 value = Convert
.ToString (GetBoundPropertyValue (bin
.ValueField
));
693 if (String
.IsNullOrEmpty (value)) {
694 if (bin
.Value
.Length
> 0)
696 else if (bin
.Text
.Length
> 0)
699 if (!String
.IsNullOrEmpty (value))
702 Text
= Value
= GetDefaultBoundText ();
705 INavigateUIData navigateUIData
= hierarchyData
as INavigateUIData
;
706 if (navigateUIData
!= null) {
707 SelectAction
= TreeNodeSelectAction
.None
;
708 Text
= navigateUIData
.ToString ();
709 NavigateUrl
= navigateUIData
.NavigateUrl
;
710 ToolTip
= navigateUIData
.Description
;
714 internal void SetDataItem (object item
)
719 internal void SetDataPath (string path
)
724 internal void SetDataBound (bool bound
)
729 string GetDefaultBoundText ()
731 if (hierarchyData
!= null)
732 return hierarchyData
.ToString ();
733 else if (dataItem
!= null)
734 return dataItem
.ToString ();
739 string GetDataItemType ()
741 if (hierarchyData
!= null)
742 return hierarchyData
.Type
;
743 else if (dataItem
!= null)
744 return dataItem
.GetType().ToString ();
749 internal bool IsParentNode
{
750 get { return ChildNodes.Count > 0 || (PopulateOnDemand && !Populated); }
753 internal bool IsLeafNode
{
754 get { return !IsParentNode; }
757 internal bool IsRootNode
{
758 get { return Depth == 0; }
761 TreeNodeBinding
GetBinding ()
767 binding
= tree
.FindBindingForNode (GetDataItemType (), Depth
);
772 object GetBoundPropertyValue (string name
)
774 if (boundProperties
== null) {
775 if (hierarchyData
!= null)
776 boundProperties
= TypeDescriptor
.GetProperties (hierarchyData
);
778 boundProperties
= TypeDescriptor
.GetProperties (dataItem
);
781 PropertyDescriptor prop
= boundProperties
.Find (name
, true);
783 throw new InvalidOperationException ("Property '" + name
+ "' not found in data bound item");
785 if (hierarchyData
!= null)
786 return prop
.GetValue (hierarchyData
);
788 return prop
.GetValue (dataItem
);
791 internal void BeginRenderText (HtmlTextWriter writer
)
793 RenderPreText (writer
);
796 internal void EndRenderText (HtmlTextWriter writer
)
798 RenderPostText (writer
);
801 protected virtual void RenderPreText (HtmlTextWriter writer
)
805 protected virtual void RenderPostText (HtmlTextWriter writer
)