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 ?
RenderRepeater(HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)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 
RenderBr(HtmlTextWriter w)73 		void RenderBr (HtmlTextWriter w)
74 		{
75 			w.Write ("<br />");
76 		}
RenderList(HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)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 		}
RenderVert(HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)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 
RenderHoriz(HtmlTextWriter w, IRepeatInfoUser user, Style controlStyle, WebControl baseControl)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 
index_vert(int rows, int cols, int r, int c, int items)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 
RenderBeginTag(HtmlTextWriter w, Style s, WebControl wc)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")]
PrintValues(IRepeatInfoUser riu)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 }
537