2007-08-05 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / RepeatInfo.cs
1 //
2 // System.Web.UI.WebControls.RepeatInfo.cs
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@novell.com)
6 //
7 // (C) 2005 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
29 //#define DEBUG_REPEAT_INFO
30
31 using System.Diagnostics;
32 using System.ComponentModel;
33 using System.Security.Permissions;
34
35 namespace System.Web.UI.WebControls {
36
37         // CAS - no inheritance demand required because the class is sealed
38         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39         public sealed class RepeatInfo {
40
41                 // What is baseControl for ?
42                 public void RenderRepeater (HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)
43                 {
44                         PrintValues (user);
45
46                         if (RepeatDirection == RepeatDirection.Vertical)
47                                 RenderVert (w, user, controlStyle, baseControl);
48                         else
49                                 RenderHoriz (w, user, controlStyle, baseControl);
50                 }
51
52                 void RenderBr (HtmlTextWriter w)
53                 {
54 #if NET_2_0
55                         w.Write ("<br />");
56 #else
57                         // grrr, not xhtml...
58                         w.Write ("<br>");
59 #endif
60
61                 }
62
63                 void RenderVert (HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl) 
64                 {
65                         int itms = user.RepeatedItemCount;
66                         // total number of rows/columns in our table
67                         int cols = RepeatColumns == 0 ? 1 : RepeatColumns;
68                         // this gets ceil (itms / cols)
69                         int rows = (itms + cols - 1) / cols;
70                         bool sep = user.HasSeparators;
71                         bool oti = OuterTableImplied;
72                         int hdr_span = cols * ((sep && cols != 1) ? 2 : 1);
73
74                         bool table = RepeatLayout == RepeatLayout.Table && !oti;
75
76 #if NET_2_0
77                         bool show_empty_trailing_items = true;
78                         bool show_empty_trailing_sep = true;
79 #else
80                         bool show_empty_trailing_items = false;
81                         bool show_empty_trailing_sep = false;
82 #endif
83                         
84                         if (! oti)
85                                 RenderBeginTag (w, controlStyle, baseControl);
86
87                         if (Caption.Length > 0) {
88                                 if (CaptionAlign != TableCaptionAlign.NotSet)
89                                         w.AddAttribute (HtmlTextWriterAttribute.Align, CaptionAlign.ToString());
90
91                                 w.RenderBeginTag (HtmlTextWriterTag.Caption);
92                                 w.Write (Caption);
93                                 w.RenderEndTag ();
94
95                         }
96
97                         // Render the header
98                         if (user.HasHeader) {
99                                 if (oti)
100                                         user.RenderItem (ListItemType.Header, -1, this, w);
101                                 else if (table) {
102                                         w.RenderBeginTag (HtmlTextWriterTag.Tr);
103                                         // Make sure the header takes up the full width. We have two
104                                         // columns per item if we are using separators, otherwise
105                                         // one per item.
106                                         if (hdr_span != 1)
107                                                 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
108
109                                         if (UseAccessibleHeader)
110                                                 w.AddAttribute ("scope", "col", false);
111                                         
112                                         Style s = user.GetItemStyle (ListItemType.Header, -1);
113                                         if (s != null)
114                                                 s.AddAttributesToRender (w);
115
116                                         if (UseAccessibleHeader)
117                                                 w.RenderBeginTag (HtmlTextWriterTag.Th);
118                                         else
119                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
120
121                                         user.RenderItem (ListItemType.Header, -1, this, w);
122                                         w.RenderEndTag (); // td
123                                         w.RenderEndTag (); // tr
124                                 } else {
125                                         user.RenderItem (ListItemType.Header, -1, this, w);
126                                         RenderBr (w);
127                                 }
128                         }
129
130                         for (int r = 0; r < rows; r ++) {
131                                 if (table)
132                                         w.RenderBeginTag (HtmlTextWriterTag.Tr);
133                                 
134                                 for (int c = 0; c < cols; c ++) {
135                                         // Find the item number we are in according to the repeat
136                                         // direction.
137                                         int item = index_vert (rows, cols, r, c, itms);
138
139                                         // This item is blank because there there not enough items
140                                         // to make a full row.
141                                         if (!show_empty_trailing_items && item >= itms)
142                                                 continue;
143
144                                         if (table) {
145                                                 Style s = null;
146                                                 if (item < itms)
147                                                         s = user.GetItemStyle (ListItemType.Item, item);
148                                                 if (s != null)
149                                                         s.AddAttributesToRender (w);
150                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
151                                         }
152                                         
153                                         if (item < itms)
154                                                 user.RenderItem (ListItemType.Item, item, this, w);
155
156                                         if (table)
157                                                 w.RenderEndTag (); // td
158
159                                         if (sep && cols != 1) {
160                                                 if (table) {
161                                                         if (item < itms - 1) {
162                                                                 Style s = user.GetItemStyle (ListItemType.Separator, item);
163                                                                 if (s != null)
164                                                                         s.AddAttributesToRender (w);
165                                                         }
166                                                         if (item < itms - 1 || show_empty_trailing_sep)
167                                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
168                                                 }
169
170                                                 if (item < itms - 1)
171                                                         user.RenderItem (ListItemType.Separator, item, this, w);
172
173                                                 if (table && (item < itms - 1 || show_empty_trailing_sep))
174                                                         w.RenderEndTag (); // td
175                                         }
176                                 }
177                                 if (oti) {
178                                 } else if (table) {
179                                         w.RenderEndTag (); // tr
180                                 } else if (r != rows - 1) {
181                                         RenderBr(w);
182                                 }
183                                 
184                                 if (sep && r != rows - 1 /* no sep on last item */ && cols == 1) {
185                                         if (table) {
186                                                 w.RenderBeginTag (HtmlTextWriterTag.Tr);
187                                                 Style s = user.GetItemStyle (ListItemType.Separator, r);
188                                                 if (s != null)
189                                                         s.AddAttributesToRender (w);
190                                         
191                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
192                                         } else if (oti) {
193 #if !NET_2_0
194                                                 /* 2.0 doesn't render this <br /> */
195                                                 RenderBr (w);
196 #endif
197                                         }
198                                         
199                                         user.RenderItem (ListItemType.Separator, r, this, w);
200
201                                         if (table) {
202                                                 w.RenderEndTag (); // td
203                                                 w.RenderEndTag (); // tr
204                                         } else if (!oti) {
205                                                 RenderBr (w);
206                                         }
207                                 }
208                         }
209
210                         // Render the footer
211                         if (user.HasFooter) {
212                                 if (oti)
213                                         user.RenderItem (ListItemType.Footer, -1, this, w);
214                                 else if (table) {
215                                         w.RenderBeginTag (HtmlTextWriterTag.Tr);
216                                         if (hdr_span != 1)
217                                                 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
218
219                                         Style s = user.GetItemStyle (ListItemType.Footer, -1);
220                                         if (s != null)
221                                                 s.AddAttributesToRender (w);
222                                         
223                                         w.RenderBeginTag (HtmlTextWriterTag.Td);
224                                         user.RenderItem (ListItemType.Footer, -1, this, w);
225                                         w.RenderEndTag (); // td
226                                         w.RenderEndTag (); // tr
227                                 } else {
228                                         // avoid dups on 0 items
229                                         if (itms != 0)
230                                                 RenderBr (w);
231                                         user.RenderItem (ListItemType.Footer, -1, this, w);
232                                 }
233                         }
234                         if (! oti)
235                                 w.RenderEndTag (); // table/span
236                         
237                 }
238                 
239                 void RenderHoriz (HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl) 
240                 {
241                         int itms = user.RepeatedItemCount;
242                         // total number of rows/columns in our table
243                         int cols = RepeatColumns == 0 ? itms : RepeatColumns;
244                         // this gets ceil (itms / cols)
245                         int rows = cols == 0 ? 0 : (itms + cols - 1) / cols;
246                         bool sep = user.HasSeparators;
247                         //bool oti = OuterTableImplied;
248                         int hdr_span = cols * (sep ? 2 : 1);
249
250                         bool table = RepeatLayout == RepeatLayout.Table;
251
252 #if NET_2_0
253                         bool show_empty_trailing_items = true;
254                         bool show_empty_trailing_sep = true;
255 #else
256                         bool show_empty_trailing_items = false;
257                         bool show_empty_trailing_sep = false;
258 #endif
259
260                         RenderBeginTag (w, controlStyle, baseControl);
261
262                         if (Caption.Length > 0) {
263                                 if (CaptionAlign != TableCaptionAlign.NotSet)
264                                         w.AddAttribute (HtmlTextWriterAttribute.Align, CaptionAlign.ToString());
265
266                                 w.RenderBeginTag (HtmlTextWriterTag.Caption);
267                                 w.Write (Caption);
268                                 w.RenderEndTag ();
269
270                         }
271                         
272                         // Render the header
273                         if (user.HasHeader) {
274                                 if (table) {
275                                         w.RenderBeginTag (HtmlTextWriterTag.Tr);
276                                         // Make sure the header takes up the full width. We have two
277                                         // columns per item if we are using separators, otherwise
278                                         // one per item.
279                                         if (hdr_span != 1)
280                                                 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
281
282                                         if (UseAccessibleHeader)
283                                                 w.AddAttribute ("scope", "col", false);
284
285                                         Style s = user.GetItemStyle (ListItemType.Header, -1);
286                                         if (s != null)
287                                                 s.AddAttributesToRender (w);
288
289                                         if (UseAccessibleHeader)
290                                                 w.RenderBeginTag (HtmlTextWriterTag.Th);
291                                         else
292                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
293
294                                         user.RenderItem (ListItemType.Header, -1, this, w);
295                                         w.RenderEndTag (); // td
296                                         w.RenderEndTag (); // tr
297                                 } else {
298                                         user.RenderItem (ListItemType.Header, -1, this, w);
299                                         if (!table && RepeatColumns != 0 && itms != 0)
300                                                 RenderBr (w);
301                                 }
302                         }
303                                                 
304                         for (int r = 0; r < rows; r ++) {
305                                 if (table)
306                                         w.RenderBeginTag (HtmlTextWriterTag.Tr);
307                                 
308                                 for (int c = 0; c < cols; c ++) {
309                                         // Find the item number we are in according to the repeat
310                                         // direction.
311                                         int item = r * cols + c;
312
313                                         // This item is blank because there there not enough items
314                                         // to make a full row.
315                                         if (!show_empty_trailing_items && item >= itms)
316                                                 continue;
317
318                                         if (table) {
319                                                 Style s = null;
320                                                 if (item < itms)
321                                                         s = user.GetItemStyle (ListItemType.Item, item);
322
323                                                 if (s != null)
324                                                         s.AddAttributesToRender (w);
325                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
326                                         }
327
328                                         if (item < itms)
329                                                 user.RenderItem (ListItemType.Item, item, this, w);
330
331                                         if (table)
332                                                 w.RenderEndTag (); // td
333
334                                         if (sep) {
335                                                 if (table) {
336                                                         if (item < itms - 1) {
337                                                                 Style s = user.GetItemStyle (ListItemType.Separator, item);
338                                                                 if (s != null)
339                                                                         s.AddAttributesToRender (w);
340                                                         }
341                                                         if (item < itms - 1 || show_empty_trailing_sep)
342                                                                 w.RenderBeginTag (HtmlTextWriterTag.Td);
343                                                 }
344
345                                                 if (item < itms - 1)
346                                                         user.RenderItem (ListItemType.Separator, item, this, w);
347
348                                                 if (table && (item < itms - 1 || show_empty_trailing_sep))
349                                                         w.RenderEndTag (); // td
350                                         }
351                                 }
352
353                                 if (table) {
354                                         //      if (!oti)
355                                                 w.RenderEndTag (); // tr
356                                 } else if (!(r == rows -1 && RepeatColumns == 0))
357                                         RenderBr (w);
358                                 
359                         }
360
361                         // Render the footer
362                         if (user.HasFooter) {
363                                 if (table) {
364                                         w.RenderBeginTag (HtmlTextWriterTag.Tr);
365                                         if (hdr_span != 1)
366                                                 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
367
368                                         Style s = user.GetItemStyle (ListItemType.Footer, -1);
369                                         if (s != null)
370                                                 s.AddAttributesToRender (w);
371                                         
372                                         w.RenderBeginTag (HtmlTextWriterTag.Td);
373                                         user.RenderItem (ListItemType.Footer, -1, this, w);
374                                         w.RenderEndTag (); // td
375                                         w.RenderEndTag (); // tr
376                                 } else {
377                                         user.RenderItem (ListItemType.Footer, -1, this, w);
378                                 }
379                         }
380                         if (true)
381                                 w.RenderEndTag (); // table/span
382                         
383                 }
384
385                 int index_vert (int rows, int cols, int r, int c, int items)
386                 {
387                         int last = items % cols;
388
389                         if (last == 0)
390                                 last = cols;
391                         if (r == rows - 1 && c >= last)
392                                 return items;
393                         
394                         
395                         int add;
396                         int v;
397                         if (c > last){
398                                 add = last * rows + (c-last) * (rows-1);
399                                 v = add + r;
400                         } else
401                                 v = rows * c + r;
402                         
403                         return v;
404                 }
405
406                 void RenderBeginTag (HtmlTextWriter w, Style s, WebControl wc)
407                 {
408                         WebControl c;
409                         if (RepeatLayout == RepeatLayout.Table)
410                                 c = new Table ();
411                         else
412                                 c = new Label ();
413
414                         c.ID = wc.ClientID;
415                         c.CopyBaseAttributes (wc);
416                         c.ApplyStyle (s);
417                         c.Enabled = wc.Enabled;
418                         c.RenderBeginTag (w);
419                 }
420                 
421                 
422                 bool outer_table_implied;
423                 public bool OuterTableImplied {
424                         get {
425                                 return outer_table_implied;
426                         }
427                         set {
428                                 outer_table_implied = value;
429                         }
430                 }
431
432                 int repeat_cols;
433                 public int RepeatColumns {
434                         get {
435                                 return repeat_cols;
436                         }
437                         set {
438                                 repeat_cols = value;
439                         }
440                 }
441
442                 RepeatDirection dir = RepeatDirection.Vertical;
443                 public RepeatDirection RepeatDirection {
444                         get {
445                                 return dir;
446                         }
447                         set {
448                                 if (value != RepeatDirection.Horizontal &&
449                                     value != RepeatDirection.Vertical)
450                                         throw new ArgumentOutOfRangeException ();
451                                 
452                                 dir = value;
453                         }
454                 }
455
456                 RepeatLayout layout;
457                 public RepeatLayout RepeatLayout {
458                         get {
459                                 return layout;
460                         }
461                         set {
462                                 if (value != RepeatLayout.Flow &&
463                                     value != RepeatLayout.Table)
464                                         throw new ArgumentOutOfRangeException ();       
465                                 layout = value;
466                         }
467                 }
468
469                 [Conditional ("DEBUG_REPEAT_INFO")]
470                 internal void PrintValues (IRepeatInfoUser riu)
471                 {
472                         string s = String.Format ("Layout {0}; Direction {1}; Cols {2}; OuterTableImplied {3}\n" +
473                                         "User: itms {4}, hdr {5}; ftr {6}; sep {7}", RepeatLayout, RepeatDirection,
474                                         RepeatColumns, OuterTableImplied, riu.RepeatedItemCount, riu.HasSeparators, riu.HasHeader,
475                                         riu.HasFooter, riu.HasSeparators
476                                 );
477                         Console.WriteLine (s);
478                         if (HttpContext.Current != null)
479                                 HttpContext.Current.Trace.Write (s);
480                 }
481
482                 private string caption = "";
483                 private TableCaptionAlign captionAlign = TableCaptionAlign.NotSet; 
484                 private  bool useAccessibleHeader = false; 
485
486                 [WebSysDescription ("")]
487                 [WebCategory ("Accessibility")]
488                 public string Caption {
489                         get {return caption;}
490                         set { caption = value; }
491                 }
492
493                 [WebSysDescription ("")]
494                 [DefaultValue (TableCaptionAlign.NotSet)]
495                 [WebCategory ("Accessibility")]
496                 public TableCaptionAlign CaptionAlign {
497                         get {return captionAlign;}
498                         set { captionAlign = value; }
499                 }
500
501                 [WebSysDescription ("")]
502                 [DefaultValue (false)]
503                 [WebCategory ("Accessibility")]
504                 public bool UseAccessibleHeader {
505                         get {return useAccessibleHeader;}
506                         set { useAccessibleHeader = value; }            
507                 }
508
509         }
510 }