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