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