2010-03-02 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Web / System.Web.UI.WebControls / TreeNode.cs
bloba3335f80da7b39f4010e6730cd50bb0a77a77551
1 //
2 // System.Web.UI.WebControls.TreeNode.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.
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
31 #if NET_2_0
33 using System;
34 using System.Collections;
35 using System.Text;
36 using System.ComponentModel;
37 using System.Web.UI;
39 namespace System.Web.UI.WebControls
41 [ParseChildrenAttribute (true, "ChildNodes")]
42 public class TreeNode: IStateManager, ICloneable
44 StateBag ViewState = new StateBag ();
45 TreeNodeCollection nodes;
46 bool marked;
47 TreeView tree;
48 TreeNode parent;
49 int index;
50 string path;
51 int depth = -1;
53 object dataItem;
54 IHierarchyData hierarchyData;
56 bool gotBinding;
57 TreeNodeBinding binding;
58 PropertyDescriptorCollection boundProperties;
59 bool populating;
60 bool hadChildrenBeforePopulating;
62 internal TreeNode (TreeView tree)
64 Tree = tree;
67 public TreeNode ()
71 public TreeNode (string text)
73 Text = text;
76 public TreeNode (string text, string value)
78 Text = text;
79 Value = value;
82 public TreeNode (string text, string value, string imageUrl)
84 Text = text;
85 Value = value;
86 ImageUrl = imageUrl;
89 public TreeNode (string text, string value, string imageUrl, string navigateUrl, string target)
91 Text = text;
92 Value = value;
93 ImageUrl = imageUrl;
94 NavigateUrl = navigateUrl;
95 Target = target;
98 [MonoTODO ("Not implemented")]
99 protected TreeNode (TreeView owner, bool isRoot)
101 throw new NotImplementedException ();
104 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
105 [Browsable (false)]
106 public int Depth {
107 get {
108 if (depth != -1) return depth;
109 depth = 0;
110 TreeNode nod = parent;
111 while (nod != null) {
112 depth++;
113 nod = nod.parent;
115 return depth;
119 void ResetPathData ()
121 path = null;
122 depth = -1;
123 gotBinding = false;
124 if (nodes != null) {
125 foreach (TreeNode node in nodes)
126 node.ResetPathData ();
130 internal TreeView Tree {
131 get { return tree; }
132 set {
133 if (SelectedFlag) {
134 if (value != null)
135 value.SetSelectedNode (this, false);
136 if (tree != null)
137 tree.SetSelectedNode (null, false);
139 tree = value;
140 if (nodes != null)
141 nodes.SetTree (tree);
142 ResetPathData ();
143 if (PopulateOnDemand && !Populated && Expanded.HasValue && Expanded.Value)
144 Populate ();
148 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
149 [DefaultValue (false)]
150 [Browsable (false)]
151 public bool DataBound {
152 get { return ViewState ["DataBound"] == null ? false : (bool) ViewState ["DataBound"]; }
153 private set { ViewState ["DataBound"] = value; }
156 [DefaultValue (null)]
157 [Browsable (false)]
158 public object DataItem {
159 get { return dataItem; }
162 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
163 [DefaultValue ("")]
164 [Browsable (false)]
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 {
172 get {
173 object o = ViewState ["Checked"];
174 if (o != null) return (bool)o;
175 return false;
177 set {
178 ViewState ["Checked"] = value;
179 if (tree != null)
180 tree.NotifyCheckChanged (this);
184 [DefaultValue (null)]
185 [MergableProperty (false)]
186 [Browsable (false)]
187 [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
188 public TreeNodeCollection ChildNodes {
189 get {
190 if (nodes == null) {
191 nodes = new TreeNodeCollection (this);
193 if (IsTrackingViewState)
194 ((IStateManager)nodes).TrackViewState();
196 return nodes;
200 [DefaultValue (null)]
201 public bool? Expanded {
202 get {
203 object o = ViewState ["Expanded"];
204 return (bool?)o;
206 set {
207 bool? current = (bool?) ViewState ["Expanded"];
208 if (current == value)
209 return;
210 ViewState ["Expanded"] = value;
211 if (tree != null)
212 tree.NotifyExpandedChanged (this);
213 if (PopulateOnDemand && !Populated && value.HasValue && value.Value)
214 Populate ();
218 [Localizable (true)]
219 [DefaultValue ("")]
220 public string ImageToolTip {
221 get {
222 object o = ViewState ["ImageToolTip"];
223 if (o != null)
224 return (string)o;
225 return String.Empty;
227 set { ViewState ["ImageToolTip"] = value; }
230 [DefaultValue ("")]
231 [UrlProperty]
232 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
233 public string ImageUrl {
234 get {
235 object o = ViewState ["ImageUrl"];
236 if (o != null)
237 return (string)o;
238 return String.Empty;
240 set { ViewState ["ImageUrl"] = value; }
243 [DefaultValue ("")]
244 [UrlProperty]
245 [Editor ("System.Web.UI.Design.UrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
246 public string NavigateUrl {
247 get {
248 object o = ViewState ["NavigateUrl"];
249 if (o != null)
250 return (string)o;
251 return String.Empty;
253 set { ViewState ["NavigateUrl"] = value; }
256 internal bool HadChildrenBeforePopulating {
257 get { return hadChildrenBeforePopulating; }
258 set {
259 if (populating)
260 return;
262 hadChildrenBeforePopulating = value;
266 [DefaultValue (false)]
267 public bool PopulateOnDemand {
268 get {
269 object o = ViewState ["PopulateOnDemand"];
270 if (o != null)
271 return (bool)o;
272 return false;
274 set {
275 ViewState ["PopulateOnDemand"] = value;
276 if (value && nodes != null && nodes.Count > 0)
277 HadChildrenBeforePopulating = true;
278 else
279 HadChildrenBeforePopulating = false;
283 [DefaultValue (TreeNodeSelectAction.Select)]
284 public TreeNodeSelectAction SelectAction {
285 get {
286 object o = ViewState ["SelectAction"];
287 if (o != null)
288 return (TreeNodeSelectAction)o;
289 return TreeNodeSelectAction.Select;
291 set { ViewState ["SelectAction"] = value; }
294 [DefaultValue (null)]
295 public bool? ShowCheckBox {
296 get {
297 object o = ViewState ["ShowCheckBox"];
298 return (bool?)o;
300 set { ViewState ["ShowCheckBox"] = value; }
303 internal bool ShowCheckBoxInternal {
304 get {
305 if (ShowCheckBox.HasValue)
306 return ShowCheckBox.Value;
307 else
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);
315 [DefaultValue ("")]
316 public string Target {
317 get {
318 object o = ViewState ["Target"];
319 if(o != null)
320 return (string)o;
321 return String.Empty;
323 set { ViewState ["Target"] = value; }
326 [Localizable (true)]
327 [DefaultValue ("")]
328 [WebSysDescription ("The display text of the tree node.")]
329 public string Text {
330 get {
331 object o = ViewState ["Text"];
332 if (o == null)
333 o = ViewState ["Value"];
334 if (o != null)
335 return (string)o;
336 return String.Empty;
338 set { ViewState ["Text"] = value; }
341 [Localizable (true)]
342 [DefaultValue ("")]
343 public string ToolTip {
344 get {
345 object o = ViewState ["ToolTip"];
346 if(o != null)
347 return (string)o;
348 return String.Empty;
350 set { ViewState ["ToolTip"] = value; }
353 [Localizable (true)]
354 [DefaultValue ("")]
355 public string Value {
356 get {
357 object o = ViewState ["Value"];
358 if (o == null)
359 o = ViewState ["Text"];
360 if(o != null)
361 return (string)o;
362 return String.Empty;
364 set { ViewState ["Value"] = value; }
367 [DefaultValue (false)]
368 public bool Selected {
369 get { return SelectedFlag; }
370 set {
371 SelectedFlag = value;
373 if (tree != null) {
374 if (!value && tree.SelectedNode == this)
375 tree.SetSelectedNode (null, false);
376 else if (value)
377 tree.SetSelectedNode (this, false);
382 internal virtual bool SelectedFlag {
383 get {
384 object o = ViewState ["Selected"];
385 if(o != null)
386 return (bool)o;
387 return false;
389 set { ViewState ["Selected"] = value; }
392 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
393 [Browsable (false)]
394 public TreeNode Parent {
395 get { return parent; }
398 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
399 [Browsable (false)]
400 public string ValuePath {
401 get {
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);
409 node = node.Parent;
411 return sb.ToString ();
415 internal int Index {
416 get { return index; }
417 set { index = value; ResetPathData (); }
420 internal void SetParent (TreeNode node)
422 parent = node;
423 ResetPathData ();
426 internal string Path {
427 get {
428 if (path != null)
429 return path;
430 StringBuilder sb = new StringBuilder (index.ToString());
431 TreeNode node = parent;
432 while (node != null) {
433 sb.Insert (0, '_');
434 sb.Insert (0, node.Index.ToString ());
435 node = node.Parent;
437 path = sb.ToString ();
438 return path;
442 internal bool Populated {
443 get {
444 object o = ViewState ["Populated"];
445 if (o != null)
446 return (bool) o;
447 return false;
449 set { ViewState ["Populated"] = value; }
452 internal bool HasChildData {
453 get { return nodes != null; }
456 internal void Populate ()
458 if (tree == null)
459 return;
461 populating = true;
462 tree.NotifyPopulateRequired (this);
463 populating = false;
464 Populated = true;
467 public void Collapse ()
469 Expanded = false;
472 public void CollapseAll ()
474 SetExpandedRec (false, -1);
477 public void Expand ()
479 Expanded = true;
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)
494 Expanded = expanded;
495 if (depth == 0)
496 return;
498 foreach (TreeNode nod in ChildNodes)
499 nod.SetExpandedRec (expanded, depth - 1);
502 public void Select ()
504 Selected = true;
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;
512 #else
513 Expanded = !Expanded.GetValueOrDefault(false);
514 #endif
517 void IStateManager.LoadViewState (object savedState)
519 LoadViewState (savedState);
522 protected virtual void LoadViewState (object savedState)
524 if (savedState == null)
525 return;
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)
550 return states;
552 return null;
555 void IStateManager.TrackViewState ()
557 TrackViewState ();
560 protected void TrackViewState ()
562 if (marked) return;
563 marked = true;
564 ViewState.TrackViewState();
566 if (nodes != null)
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);
581 if (nodes != null)
582 nodes.SetDirty ();
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 ());
594 return nod;
597 object ICloneable.Clone ()
599 return Clone ();
602 internal void Bind (IHierarchyData hierarchyData)
604 this.hierarchyData = hierarchyData;
605 DataBound = true;
606 DataPath = hierarchyData.Path;
607 dataItem = hierarchyData.Item;
609 TreeNodeBinding bin = GetBinding ();
610 if (bin != null) {
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)
659 Target = bin.Target;
660 } else if (bin.Target.Length > 0)
661 Target = bin.Target;
663 // Bind Text property
664 string text = null;
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)
672 text = bin.Text;
673 else if (bin.Value.Length > 0)
674 text = bin.Value;
676 if (!String.IsNullOrEmpty (text))
677 Text = 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
689 string value = null;
690 if (bin.ValueField.Length > 0) {
691 value = Convert.ToString (GetBoundPropertyValue (bin.ValueField));
693 if (String.IsNullOrEmpty (value)) {
694 if (bin.Value.Length > 0)
695 value = bin.Value;
696 else if (bin.Text.Length > 0)
697 value = bin.Text;
699 if (!String.IsNullOrEmpty (value))
700 Value = value;
701 } else {
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)
716 dataItem = item;
719 internal void SetDataPath (string path)
721 DataPath = path;
724 internal void SetDataBound (bool bound)
726 DataBound = bound;
729 string GetDefaultBoundText ()
731 if (hierarchyData != null)
732 return hierarchyData.ToString ();
733 else if (dataItem != null)
734 return dataItem.ToString ();
735 else
736 return string.Empty;
739 string GetDataItemType ()
741 if (hierarchyData != null)
742 return hierarchyData.Type;
743 else if (dataItem != null)
744 return dataItem.GetType().ToString ();
745 else
746 return string.Empty;
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 ()
763 if (tree == null)
764 return null;
765 if (gotBinding)
766 return binding;
767 binding = tree.FindBindingForNode (GetDataItemType (), Depth);
768 gotBinding = true;
769 return binding;
772 object GetBoundPropertyValue (string name)
774 if (boundProperties == null) {
775 if (hierarchyData != null)
776 boundProperties = TypeDescriptor.GetProperties (hierarchyData);
777 else
778 boundProperties = TypeDescriptor.GetProperties (dataItem);
781 PropertyDescriptor prop = boundProperties.Find (name, true);
782 if (prop == null)
783 throw new InvalidOperationException ("Property '" + name + "' not found in data bound item");
785 if (hierarchyData != null)
786 return prop.GetValue (hierarchyData);
787 else
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)
810 #endif