2 // System.Web.UI.WebControls.RepeatInfo.cs
5 // Ben Maurer (bmaurer@novell.com)
7 // (C) 2005 Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 //#define DEBUG_REPEAT_INFO
31 using System.Diagnostics;
32 using System.ComponentModel;
33 using System.Security.Permissions;
35 namespace System.Web.UI.WebControls {
37 // CAS - no inheritance demand required because the class is sealed
38 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39 public sealed class RepeatInfo {
41 // What is baseControl for ?
42 public void RenderRepeater (HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)
45 RepeatLayout layout = RepeatLayout;
46 bool listLayout = layout == RepeatLayout.OrderedList || layout == RepeatLayout.UnorderedList;
50 if ((user.HasHeader || user.HasFooter || user.HasSeparators))
51 throw new InvalidOperationException ("The UnorderedList and OrderedList layouts do not support headers, footers or separators.");
54 if (OuterTableImplied)
55 throw new InvalidOperationException ("The UnorderedList and OrderedList layouts do not support implied outer tables.");
57 int cols = RepeatColumns;
59 throw new InvalidOperationException ("The UnorderedList and OrderedList layouts do not support multi-column layouts.");
61 if (RepeatDirection == RepeatDirection.Vertical) {
63 RenderList (writer, user, controlStyle, baseControl);
65 RenderVert (writer, user, controlStyle, baseControl);
68 throw new InvalidOperationException ("The UnorderedList and OrderedList layouts only support vertical layout.");
69 RenderHoriz (writer, user, controlStyle, baseControl);
73 void RenderBr (HtmlTextWriter w)
77 void RenderList (HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)
79 int items = user.RepeatedItemCount;
80 RenderBeginTag (w, controlStyle, baseControl);
82 for (int i = 0; i < items; i++) {
84 // s = user.GetItemStyle (ListItemType.Item, i);
86 // s.AddAttributesToRender (w);
87 w.RenderBeginTag (HtmlTextWriterTag.Li);
88 user.RenderItem (ListItemType.Item, i, this, w);
89 w.RenderEndTag (); // </li>
95 void RenderVert (HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)
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;
110 RenderBeginTag (w, controlStyle, baseControl);
112 if (Caption.Length > 0) {
113 if (CaptionAlign != TableCaptionAlign.NotSet)
114 w.AddAttribute (HtmlTextWriterAttribute.Align, CaptionAlign.ToString());
116 w.RenderBeginTag (HtmlTextWriterTag.Caption);
123 if (user.HasHeader) {
125 user.RenderItem (ListItemType.Header, -1, this, w);
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
132 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
134 if (UseAccessibleHeader)
135 w.AddAttribute ("scope", "col", false);
137 Style s = user.GetItemStyle (ListItemType.Header, -1);
139 s.AddAttributesToRender (w);
141 if (UseAccessibleHeader)
142 w.RenderBeginTag (HtmlTextWriterTag.Th);
144 w.RenderBeginTag (HtmlTextWriterTag.Td);
146 user.RenderItem (ListItemType.Header, -1, this, w);
147 w.RenderEndTag (); // td
148 w.RenderEndTag (); // tr
150 user.RenderItem (ListItemType.Header, -1, this, w);
155 for (int r = 0; r < rows; r ++) {
157 w.RenderBeginTag (HtmlTextWriterTag.Tr);
159 for (int c = 0; c < cols; c ++) {
160 // Find the item number we are in according to the repeat
162 int item = index_vert (rows, cols, r, c, itms);
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)
172 s = user.GetItemStyle (ListItemType.Item, item);
174 s.AddAttributesToRender (w);
175 w.RenderBeginTag (HtmlTextWriterTag.Td);
179 user.RenderItem (ListItemType.Item, item, this, w);
182 w.RenderEndTag (); // td
184 if (sep && cols != 1) {
186 if (item < itms - 1) {
187 Style s = user.GetItemStyle (ListItemType.Separator, item);
189 s.AddAttributesToRender (w);
191 if (item < itms - 1 || show_empty_trailing_sep)
192 w.RenderBeginTag (HtmlTextWriterTag.Td);
196 user.RenderItem (ListItemType.Separator, item, this, w);
198 if (table && (item < itms - 1 || show_empty_trailing_sep))
199 w.RenderEndTag (); // td
204 w.RenderEndTag (); // tr
205 } else if (r != rows - 1) {
209 if (sep && r != rows - 1 /* no sep on last item */ && cols == 1) {
211 w.RenderBeginTag (HtmlTextWriterTag.Tr);
212 Style s = user.GetItemStyle (ListItemType.Separator, r);
214 s.AddAttributesToRender (w);
216 w.RenderBeginTag (HtmlTextWriterTag.Td);
219 user.RenderItem (ListItemType.Separator, r, this, w);
222 w.RenderEndTag (); // td
223 w.RenderEndTag (); // tr
231 if (user.HasFooter) {
233 user.RenderItem (ListItemType.Footer, -1, this, w);
235 w.RenderBeginTag (HtmlTextWriterTag.Tr);
237 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
239 Style s = user.GetItemStyle (ListItemType.Footer, -1);
241 s.AddAttributesToRender (w);
243 w.RenderBeginTag (HtmlTextWriterTag.Td);
244 user.RenderItem (ListItemType.Footer, -1, this, w);
245 w.RenderEndTag (); // td
246 w.RenderEndTag (); // tr
248 // avoid dups on 0 items
251 user.RenderItem (ListItemType.Footer, -1, this, w);
255 w.RenderEndTag (); // table/span
259 void RenderHoriz (HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)
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);
270 bool table = RepeatLayout == RepeatLayout.Table;
271 bool show_empty_trailing_items = true;
272 bool show_empty_trailing_sep = true;
274 RenderBeginTag (w, controlStyle, baseControl);
276 if (Caption.Length > 0) {
277 if (CaptionAlign != TableCaptionAlign.NotSet)
278 w.AddAttribute (HtmlTextWriterAttribute.Align, CaptionAlign.ToString());
280 w.RenderBeginTag (HtmlTextWriterTag.Caption);
287 if (user.HasHeader) {
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
294 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
296 if (UseAccessibleHeader)
297 w.AddAttribute ("scope", "col", false);
299 Style s = user.GetItemStyle (ListItemType.Header, -1);
301 s.AddAttributesToRender (w);
303 if (UseAccessibleHeader)
304 w.RenderBeginTag (HtmlTextWriterTag.Th);
306 w.RenderBeginTag (HtmlTextWriterTag.Td);
308 user.RenderItem (ListItemType.Header, -1, this, w);
309 w.RenderEndTag (); // td
310 w.RenderEndTag (); // tr
312 user.RenderItem (ListItemType.Header, -1, this, w);
313 if (!table && RepeatColumns != 0 && itms != 0)
318 for (int r = 0; r < rows; r ++) {
320 w.RenderBeginTag (HtmlTextWriterTag.Tr);
322 for (int c = 0; c < cols; c ++) {
323 // Find the item number we are in according to the repeat
325 int item = r * cols + c;
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)
335 s = user.GetItemStyle (ListItemType.Item, item);
338 s.AddAttributesToRender (w);
339 w.RenderBeginTag (HtmlTextWriterTag.Td);
343 user.RenderItem (ListItemType.Item, item, this, w);
346 w.RenderEndTag (); // td
350 if (item < itms - 1) {
351 Style s = user.GetItemStyle (ListItemType.Separator, item);
353 s.AddAttributesToRender (w);
355 if (item < itms - 1 || show_empty_trailing_sep)
356 w.RenderBeginTag (HtmlTextWriterTag.Td);
360 user.RenderItem (ListItemType.Separator, item, this, w);
362 if (table && (item < itms - 1 || show_empty_trailing_sep))
363 w.RenderEndTag (); // td
369 w.RenderEndTag (); // tr
370 } else if (!(r == rows -1 && RepeatColumns == 0))
376 if (user.HasFooter) {
378 w.RenderBeginTag (HtmlTextWriterTag.Tr);
380 w.AddAttribute (HtmlTextWriterAttribute.Colspan, hdr_span.ToString (), false);
382 Style s = user.GetItemStyle (ListItemType.Footer, -1);
384 s.AddAttributesToRender (w);
386 w.RenderBeginTag (HtmlTextWriterTag.Td);
387 user.RenderItem (ListItemType.Footer, -1, this, w);
388 w.RenderEndTag (); // td
389 w.RenderEndTag (); // tr
391 user.RenderItem (ListItemType.Footer, -1, this, w);
395 w.RenderEndTag (); // table/span
399 int index_vert (int rows, int cols, int r, int c, int items)
401 int last = items % cols;
405 if (r == rows - 1 && c >= last)
412 add = last * rows + (c-last) * (rows-1);
420 void RenderBeginTag (HtmlTextWriter w, Style s, WebControl wc)
423 switch (RepeatLayout) {
424 case RepeatLayout.Table:
428 case RepeatLayout.Flow:
431 case RepeatLayout.OrderedList:
432 c = new WebControl (HtmlTextWriterTag.Ol);
435 case RepeatLayout.UnorderedList:
436 c = new WebControl (HtmlTextWriterTag.Ul);
439 throw new InvalidOperationException (String.Format ("Unsupported RepeatLayout value '{0}'.", RepeatLayout));
443 c.CopyBaseAttributes (wc);
445 c.Enabled = wc.IsEnabled;
446 c.RenderBeginTag (w);
450 bool outer_table_implied;
451 public bool OuterTableImplied {
453 return outer_table_implied;
456 outer_table_implied = value;
461 public int RepeatColumns {
470 RepeatDirection dir = RepeatDirection.Vertical;
471 public RepeatDirection RepeatDirection {
476 if (value != RepeatDirection.Horizontal &&
477 value != RepeatDirection.Vertical)
478 throw new ArgumentOutOfRangeException ();
485 public RepeatLayout RepeatLayout {
491 outOfRange = value < RepeatLayout.Table || value > RepeatLayout.OrderedList;
493 throw new ArgumentOutOfRangeException ();
498 [Conditional ("DEBUG_REPEAT_INFO")]
499 internal void PrintValues (IRepeatInfoUser riu)
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
506 Console.WriteLine (s);
507 if (HttpContext.Current != null)
508 HttpContext.Current.Trace.Write (s);
511 string caption = String.Empty;
512 TableCaptionAlign captionAlign = TableCaptionAlign.NotSet;
513 bool useAccessibleHeader = false;
515 [WebSysDescription ("")]
516 [WebCategory ("Accessibility")]
517 public string Caption {
518 get {return caption;}
519 set { caption = value; }
522 [WebSysDescription ("")]
523 [WebCategory ("Accessibility")]
524 public TableCaptionAlign CaptionAlign {
525 get {return captionAlign;}
526 set { captionAlign = value; }
529 [WebSysDescription ("")]
530 [WebCategory ("Accessibility")]
531 public bool UseAccessibleHeader {
532 get {return useAccessibleHeader;}
533 set { useAccessibleHeader = value; }