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