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