2004-12-02 Lluis Sanchez Gual <lluis@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / TreeNode.cs
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.
27 //
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System;
34 using System.Collections;
35 using System.Text;
36 using System.ComponentModel;
37 using System.Web.UI;
38
39 namespace System.Web.UI.WebControls
40 {
41         [ParseChildrenAttribute (true, "ChildNodes")]
42         public class TreeNode: IStateManager, ICloneable
43         {
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;
52                 
53                 IHierarchyData hierarchyData;
54                 bool gotBinding;
55                 TreeNodeBinding binding;
56                 PropertyDescriptorCollection boundProperties;
57                 
58                 internal TreeNode (TreeView tree)
59                 {
60                         Tree = tree;
61                 }
62                 
63                 public TreeNode ()
64                 {
65                 }
66                 
67                 public TreeNode (string text)
68                 {
69                         Text = text;
70                 }
71                 
72                 public TreeNode (string text, string value)
73                 {
74                         Text = text;
75                         Value = value;
76                 }
77                 
78                 public TreeNode (string text, string value, string imageUrl)
79                 {
80                         Text = text;
81                         Value = value;
82                         ImageUrl = imageUrl;
83                 }
84                 
85                 public TreeNode (string text, string value, string imageUrl, string navigateUrl, string target)
86                 {
87                         Text = text;
88                         Value = value;
89                         ImageUrl = imageUrl;
90                         NavigateUrl = navigateUrl;
91                         Target = target;
92                 }
93                 
94                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
95                 [Browsable (false)]
96                 public int Depth {
97                         get {
98                                 if (depth != -1) return depth;
99                                 depth = 0;
100                                 TreeNode nod = parent;
101                                 while (nod != null) {
102                                         depth++;
103                                         nod = nod.parent;
104                                 }
105                                 return depth;
106                         }
107                 }
108                 
109                 void ResetPathData ()
110                 {
111                         path = null;
112                         depth = -1;
113                         gotBinding = false;
114                 }
115                 
116                 internal TreeView Tree {
117                         get { return tree; }
118                         set {
119                                 if (SelectedFlag) {
120                                         if (value != null)
121                                                 value.SetSelectedNode (this);
122                                         else if (tree != null)
123                                                 tree.SetSelectedNode (null);
124                                 }
125                                 tree = value;
126                                 if (nodes != null)
127                                         nodes.SetTree (tree);
128                                 ResetPathData ();
129                         }
130                 }
131                 
132                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
133                 [DefaultValue (false)]
134                 [Browsable (false)]
135                 public bool DataBound {
136                         get { return hierarchyData != null; }
137                 }
138                 
139                 [DefaultValue (null)]
140                 [Browsable (false)]
141                 public object DataItem {
142                         get {
143                                 if (hierarchyData == null) throw new InvalidOperationException ("TreeNode is not data bound.");
144                                 return hierarchyData.Item;
145                         }
146                 }
147                 
148                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
149                 [DefaultValue ("")]
150                 [Browsable (false)]
151                 public string DataPath {
152                         get {
153                                 if (hierarchyData == null) throw new InvalidOperationException ("TreeNode is not data bound.");
154                                 return hierarchyData.Path;
155                         }
156                 }
157                 
158                 [DefaultValue (false)]
159                 public virtual bool Checked {
160                         get {
161                                 object o = ViewState ["Checked"];
162                                 if (o != null) return (bool)o;
163                                 return false;
164                         }
165                         set {
166                                 ViewState ["Checked"] = value;
167                                 if (tree != null)
168                                         tree.NotifyCheckChanged (this);
169                         }
170                 }
171
172                 [DefaultValue (null)]
173                 [MergableProperty (false)]
174                 [Browsable (false)]
175                 [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
176                 public virtual TreeNodeCollection ChildNodes {
177                         get {
178                                 if (nodes == null) {
179                                         if (PopulateOnDemand && tree == null)
180                                                 return null;
181
182                                         if (DataBound)
183                                                 FillBoundChildren ();
184                                         else
185                                                 nodes = new TreeNodeCollection (this);
186                                                 
187                                         if (IsTrackingViewState)
188                                                 ((IStateManager)nodes).TrackViewState();
189                                         
190                                         if (PopulateOnDemand && !Populated) {
191                                                 Populated = true;
192                                                 Populate ();
193                                         }
194                                 }
195                                 return nodes;
196                         }
197                 }
198                 
199                 [DefaultValue (false)]
200                 public virtual bool Expanded {
201                         get {
202                                 object o = ViewState ["Expanded"];
203                                 if (o != null) return (bool)o;
204                                 return false;
205                         }
206                         set {
207                                 ViewState ["Expanded"] = value;
208                                 if (tree != null)
209                                         tree.NotifyExpandedChanged (this);
210                         }
211                 }
212
213                 [Localizable (true)]
214                 [DefaultValue ("")]
215                 public virtual string ImageToolTip {
216                         get {
217                                 object o = ViewState ["ImageToolTip"];
218                                 if (o != null) return (string)o;
219                                 if (DataBound) {
220                                         TreeNodeBinding bin = GetBinding ();
221                                         if (bin != null) {
222                                                 if (bin.ImageToolTipField != "")
223                                                         return (string) GetBoundPropertyValue (bin.ImageToolTipField);
224                                                 return bin.ImageToolTip;
225                                         }
226                                 }
227                                 return "";
228                         }
229                         set {
230                                 ViewState ["ImageToolTip"] = value;
231                         }
232                 }
233                 
234                 [DefaultValue ("")]
235                 [UrlProperty]
236                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
237                 public virtual string ImageUrl {
238                         get {
239                                 object o = ViewState ["ImageUrl"];
240                                 if (o != null) return (string)o;
241                                 if (DataBound) {
242                                         TreeNodeBinding bin = GetBinding ();
243                                         if (bin != null) {
244                                                 if (bin.ImageUrlField != "")
245                                                         return (string) GetBoundPropertyValue (bin.ImageUrlField);
246                                                 return bin.ImageUrl;
247                                         }
248                                 }
249                                 return "";
250                         }
251                         set {
252                                 ViewState ["ImageUrl"] = value;
253                         }
254                 }
255
256                 [DefaultValue ("")]
257                 [UrlProperty]
258                 [Editor ("System.Web.UI.Design.UrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
259                 public virtual string NavigateUrl {
260                         get {
261                                 object o = ViewState ["NavigateUrl"];
262                                 if (o != null) return (string)o;
263                                 if (DataBound) {
264                                         TreeNodeBinding bin = GetBinding ();
265                                         if (bin != null) {
266                                                 if (bin.NavigateUrlField != "")
267                                                         return (string) GetBoundPropertyValue (bin.NavigateUrlField);
268                                                 return bin.NavigateUrl;
269                                         }
270                                 }
271                                 return "";
272                         }
273                         set {
274                                 ViewState ["NavigateUrl"] = value;
275                         }
276                 }
277
278                 [DefaultValue (false)]
279                 public bool PopulateOnDemand {
280                         get {
281                                 object o = ViewState ["PopulateOnDemand"];
282                                 if (o != null) return (bool)o;
283                                 if (DataBound) {
284                                         TreeNodeBinding bin = GetBinding ();
285                                         if (bin != null)
286                                                 return bin.PopulateOnDemand;
287                                 }
288                                 return false;
289                         }
290                         set {
291                                 ViewState ["PopulateOnDemand"] = value;
292                         }
293                 }
294
295                 [DefaultValue (TreeNodeSelectAction.Select)]
296                 public TreeNodeSelectAction SelectAction {
297                         get {
298                                 object o = ViewState ["SelectAction"];
299                                 if (o != null) return (TreeNodeSelectAction)o;
300                                 if (DataBound) {
301                                         TreeNodeBinding bin = GetBinding ();
302                                         if (bin != null)
303                                                 return bin.SelectAction;
304                                 }
305                                 return TreeNodeSelectAction.Select;
306                         }
307                         set {
308                                 ViewState ["SelectAction"] = value;
309                         }
310                 }
311
312                 [DefaultValue (false)]
313                 public bool ShowCheckBox {
314                         get {
315                                 object o = ViewState ["ShowCheckBox"];
316                                 if (o != null) return (bool)o;
317                                 if (DataBound) {
318                                         TreeNodeBinding bin = GetBinding ();
319                                         if (bin != null)
320                                                 return bin.ShowCheckBox;
321                                 }
322                                 return false;
323                         }
324                         set {
325                                 ViewState ["ShowCheckBox"] = value;
326                         }
327                 }
328                 
329                 internal bool IsShowCheckBoxSet {
330                         get { return ViewState ["ShowCheckBox"] != null; }
331                 }
332
333                 [DefaultValue ("")]
334                 public virtual string Target {
335                         get {
336                                 object o = ViewState ["Target"];
337                                 if(o != null) return (string)o;
338                                 if (DataBound) {
339                                         TreeNodeBinding bin = GetBinding ();
340                                         if (bin != null) {
341                                                 if (bin.TargetField != "")
342                                                         return (string) GetBoundPropertyValue (bin.TargetField);
343                                                 return bin.Target;
344                                         }
345                                 }
346                                 return "";
347                         }
348                         set {
349                                 ViewState ["Target"] = value;
350                         }
351                 }
352
353                 [Localizable (true)]
354                 [DefaultValue ("")]
355                 [WebSysDescription ("The display text of the tree node.")]
356                 public virtual string Text {
357                         get {
358                                 object o = ViewState ["Text"];
359                                 if (o != null) return (string)o;
360                                 if (DataBound) {
361                                         TreeNodeBinding bin = GetBinding ();
362                                         if (bin != null) {
363                                                 string text;
364                                                 if (bin.TextField != "")
365                                                         text = (string) GetBoundPropertyValue (bin.TextField);
366                                                 else if (bin.Text != "")
367                                                         text = bin.Text;
368                                                 else
369                                                         text = hierarchyData.ToString ();
370                                                         
371                                                 if (bin.FormatString.Length != 0)
372                                                         text = string.Format (bin.FormatString, text);
373                                                 return text;
374                                         }
375                                         return hierarchyData.ToString ();
376                                 }
377                                 return "";
378                         }
379                         set {
380                                 ViewState ["Text"] = value;
381                         }
382                 }
383
384                 [Localizable (true)]
385                 [DefaultValue ("")]
386                 public virtual string ToolTip {
387                         get {
388                                 object o = ViewState ["ToolTip"];
389                                 if(o != null) return (string)o;
390                                 if (DataBound) {
391                                         TreeNodeBinding bin = GetBinding ();
392                                         if (bin != null) {
393                                                 if (bin.ToolTipField != "")
394                                                         return (string) GetBoundPropertyValue (bin.ToolTipField);
395                                                 return bin.ToolTip;
396                                         }
397                                 }
398                                 return "";
399                         }
400                         set {
401                                 ViewState ["ToolTip"] = value;
402                         }
403                 }
404
405                 [Localizable (true)]
406                 [DefaultValue ("")]
407                 public virtual string Value {
408                         get {
409                                 object o = ViewState ["Value"];
410                                 if(o != null) return (string)o;
411                                 if (DataBound) {
412                                         TreeNodeBinding bin = GetBinding ();
413                                         if (bin != null) {
414                                                 if (bin.ValueField != "")
415                                                         return (string) GetBoundPropertyValue (bin.ValueField);
416                                                 if (bin.Value != "")
417                                                         return bin.Value;
418                                         }
419                                         return hierarchyData.ToString ();
420                                 }
421                                 return "";
422                         }
423                         set {
424                                 ViewState ["Value"] = value;
425                         }
426                 }
427                 
428                 [DefaultValue (false)]
429                 public virtual bool Selected {
430                         get {
431                                 return SelectedFlag;
432                         }
433                         set {
434                                 if (tree != null) {
435                                         if (!value && tree.SelectedNode == this)
436                                                 tree.SetSelectedNode (null);
437                                         else if (value)
438                                                 tree.SetSelectedNode (this);
439                                 }
440                                 else
441                                         SelectedFlag = value;
442                         }
443                 }
444                 
445                 internal virtual bool SelectedFlag {
446                         get {
447                                 object o = ViewState ["Selected"];
448                                 if(o != null) return (bool)o;
449                                 return false;
450                         }
451                         set {
452                                 ViewState ["Selected"] = value;
453                         }
454                 }
455                 
456                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
457                 [Browsable (false)]
458                 public TreeNode Parent {
459                         get { return parent; }
460                 }
461                 
462                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
463                 [Browsable (false)]
464                 public string ValuePath {
465                         get {
466                                 if (tree == null) return Value;
467                                 
468                                 StringBuilder sb = new StringBuilder (Value);
469                                 TreeNode node = parent;
470                                 while (node != null) {
471                                         sb.Insert (0, tree.PathSeparator);
472                                         sb.Insert (0, node.Value);
473                                         node = node.Parent;
474                                 }
475                                 return sb.ToString ();
476                         }
477                 }
478                 
479                 internal int Index {
480                         get { return index; }
481                         set { index = value; ResetPathData (); }
482                 }
483                 
484                 internal void SetParent (TreeNode node) {
485                         parent = node;
486                         ResetPathData ();
487                 }
488                 
489                 internal string Path {
490                         get {
491                                 if (path != null) return path;
492                                 StringBuilder sb = new StringBuilder (index.ToString());
493                                 TreeNode node = parent;
494                                 while (node != null) {
495                                         sb.Insert (0, '_');
496                                         sb.Insert (0, node.Index.ToString ());
497                                         node = node.Parent;
498                                 }
499                                 path = sb.ToString ();
500                                 return path;
501                         }
502                 }
503                 
504                 internal bool Populated {
505                         get {
506                                 object o = ViewState ["Populated"];
507                                 if (o != null) return (bool) o;
508                                 return false;
509                         }
510                         set {
511                                 ViewState ["Populated"] = value;
512                         }
513                 }
514
515                 internal bool HasChildData {
516                         get { return nodes != null; }
517                 }
518                 
519                 protected virtual void Populate ()
520                 {
521                         tree.NotifyPopulateRequired (this);
522                 }
523                 
524                 public void Collapse ()
525                 {
526                         Expanded = false;
527                 }
528
529                 public void CollapseAll ()
530                 {
531                         SetExpandedRec (false, -1);
532                 }
533
534                 public void Expand ()
535                 {
536                         Expanded = true;
537                 }
538
539                 internal void Expand (int depth)
540                 {
541                         SetExpandedRec (true, depth);
542                 }
543
544                 public void ExpandAll ()
545                 {
546                         SetExpandedRec (true, -1);
547                 }
548                 
549                 void SetExpandedRec (bool expanded, int depth)
550                 {
551                         Expanded = expanded;
552                         if (depth == 0) return;
553                         
554                         foreach (TreeNode nod in ChildNodes)
555                                 nod.SetExpandedRec (expanded, depth - 1);
556                 }
557                 
558                 public void Select ()
559                 {
560                         Selected = true;
561                 }
562                 
563                 public void ToggleExpandState ()
564                 {
565                         Expanded = !Expanded;
566                 }
567
568                 public void LoadViewState (object savedState)
569                 {
570                         if (savedState == null)
571                                 return;
572
573                         object[] states = (object[]) savedState;
574                         ViewState.LoadViewState (states [0]);
575                         
576                         if (tree != null && SelectedFlag)
577                                 tree.SetSelectedNode (this);
578                         
579                         if (!PopulateOnDemand || Populated)
580                                 ((IStateManager)ChildNodes).LoadViewState (states [1]);
581                 }
582                 
583                 public object SaveViewState ()
584                 {
585                         object[] states = new object[2];
586                         states[0] = ViewState.SaveViewState();
587                         states[1] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
588                         
589                         for (int i = 0; i < states.Length; i++) {
590                                 if (states [i] != null)
591                                         return states;
592                         }
593                         return null;
594                 }
595                 
596                 public void TrackViewState ()
597                 {
598                         if (marked) return;
599                         marked = true;
600                         ViewState.TrackViewState();
601
602                         if (nodes != null)
603                                 ((IStateManager)nodes).TrackViewState ();
604                 }
605                 
606                 public bool IsTrackingViewState
607                 {
608                         get { return marked; }
609                 }
610                 
611                 internal void SetDirty ()
612                 {
613                         ViewState.SetDirty ();
614                 }
615                 
616                 public object Clone ()
617                 {
618                         TreeNode nod = new TreeNode ();
619                         foreach (DictionaryEntry e in ViewState)
620                                 nod.ViewState [(string)e.Key] = e.Value;
621                                 
622                         foreach (TreeNode c in ChildNodes)
623                                 nod.ChildNodes.Add ((TreeNode)c.Clone ());
624                                 
625                         return nod;
626                 }
627                 
628                 internal void Bind (IHierarchyData hierarchyData)
629                 {
630                         this.hierarchyData = hierarchyData;
631                 }
632                 
633                 internal bool IsParentNode {
634                         get { return ChildNodes.Count > 0 && Parent != null; }
635                 }
636                 
637                 internal bool IsLeafNode {
638                         get { return ChildNodes.Count == 0; }
639                 }
640                 
641                 internal bool IsRootNode {
642                         get { return ChildNodes.Count > 0 && Parent == null; }
643                 }
644                 
645                 TreeNodeBinding GetBinding ()
646                 {
647                         if (tree == null) return null;
648                         if (gotBinding) return binding;
649                         binding = tree.FindBindingForNode (hierarchyData.Type, Depth);
650                         gotBinding = true;
651                         return binding;
652                 }
653                 
654                 object GetBoundPropertyValue (string name)
655                 {
656                         if (boundProperties == null) {
657                                 ICustomTypeDescriptor desc = hierarchyData as ICustomTypeDescriptor;
658                                 if (desc == null)
659                                         throw new InvalidOperationException ("Property '" + name + "' not found in data bound item");
660                                 boundProperties = desc.GetProperties ();
661                         }
662                         
663                         PropertyDescriptor prop = boundProperties.Find (name, true);
664                         if (prop == null)
665                                 throw new InvalidOperationException ("Property '" + name + "' not found in data bound item");
666                         return prop.GetValue (hierarchyData);
667                 }
668
669                 void FillBoundChildren ()
670                 {
671                         nodes = new TreeNodeCollection (this);
672                         if (!hierarchyData.HasChildren) return;
673                         if (tree.MaxDataBindDepth != -1 && Depth >= tree.MaxDataBindDepth) return;
674
675                         IHierarchicalEnumerable e = hierarchyData.GetChildren ();
676                         foreach (object obj in e) {
677                                 IHierarchyData hdata = e.GetHierarchyData (obj);
678                                 TreeNode node = new TreeNode ();
679                                 node.Bind (hdata);
680                                 nodes.Add (node);
681                         }
682                 }
683         }
684 }
685
686 #endif