1 /**
2 * Licensed under the Artistic License; you may not use this file
3 * except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://displaytag.sourceforge.net/license.html
7 *
8 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12 package org.displaytag.model;
13
14 import java.util.Comparator;
15
16 import org.apache.commons.beanutils.Converter;
17 import org.apache.commons.lang.StringUtils;
18 import org.apache.commons.lang.builder.ToStringBuilder;
19 import org.apache.commons.lang.builder.ToStringStyle;
20 import org.displaytag.decorator.DisplaytagColumnDecorator;
21 import org.displaytag.exception.DecoratorException;
22 import org.displaytag.exception.ObjectLookupException;
23 import org.displaytag.properties.SortOrderEnum;
24 import org.displaytag.util.Href;
25 import org.displaytag.util.HtmlAttributeMap;
26 import org.displaytag.util.HtmlTagUtil;
27 import org.displaytag.util.MultipleHtmlAttribute;
28 import org.displaytag.util.TagConstants;
29
30
31 /**
32 * DataObject representing the column header. The header cell contains all the properties common to cells in the same
33 * column.
34 * @author Fabrizio Giustina
35 * @version $Revision: 1087 $ ($Author: rapruitt $)
36 */
37 public class HeaderCell
38 {
39
40 /**
41 * Map containing the html tag attributes for cells (td).
42 */
43 private HtmlAttributeMap htmlAttributes;
44
45 /**
46 * Map containing the html tag attributes for header cells (td).
47 */
48 private HtmlAttributeMap headerAttributes;
49
50 /**
51 * base href for creating dinamic links.
52 */
53 private Href href;
54
55 /**
56 * param name used in adding a link.
57 */
58 private String paramName;
59
60 /**
61 * property of the object where to get the param value from.
62 */
63 private String paramProperty;
64
65 /**
66 * column title.
67 */
68 private String title;
69
70 /**
71 * is the column sortable?
72 */
73 private boolean sortable;
74
75 /**
76 * Name given to the server when sorting this column
77 */
78 private String sortName;
79
80 /**
81 * ColumnDecorators.
82 */
83 private DisplaytagColumnDecorator[] columnDecorators;
84
85 /**
86 * column number.
87 */
88 private int columnNumber;
89
90 /**
91 * is the column sorted?
92 */
93 private boolean alreadySorted;
94
95 /**
96 * property name to look up in the bean.
97 */
98 private String beanPropertyName;
99
100 /**
101 * show null values?
102 */
103 private boolean showNulls;
104
105 /**
106 * max length of cell content.
107 */
108 private int maxLength;
109
110 /**
111 * max number of words for cell content.
112 */
113 private int maxWords;
114
115 /**
116 * group the column?
117 */
118 private int group;
119
120 /**
121 * Name of the non-decorated property used during sorting.
122 */
123 private String sortPropertyName;
124
125 /**
126 * Should we be attempting to tabulate the totals?
127 */
128 private boolean totaled;
129
130 /**
131 * Defalt sort order for this column.
132 */
133 private SortOrderEnum defaultSortOrder;
134
135 /**
136 * The running total for the column.
137 */
138 private double total;
139
140 /**
141 * Use this comparator for sorting.
142 */
143 private Comparator comparator;
144
145 /**
146 * getter for the grouping index.
147 * @return 0 if the column is not grouped or the grouping order
148 */
149 public int getGroup()
150 {
151 return this.group;
152 }
153
154 /**
155 * setter for the grouping index.
156 * @param groupingOrder int grouping order (>0)
157 */
158 public void setGroup(int groupingOrder)
159 {
160 this.group = groupingOrder;
161 }
162
163 /**
164 * getter for the max number of characters to display in the column.
165 * @return int number of characters to display in the column
166 */
167 public int getMaxLength()
168 {
169 return this.maxLength;
170 }
171
172 /**
173 * setter for the max number of characters to display in the column.
174 * @param numOfChars number of characters to display in the column
175 */
176 public void setMaxLength(int numOfChars)
177 {
178 this.maxLength = numOfChars;
179 }
180
181 /**
182 * getter for the max number of words to display in the column.
183 * @return int number of words to display in the column
184 */
185 public int getMaxWords()
186 {
187 return this.maxWords;
188 }
189
190 /**
191 * setter for the max number of words to display in the column.
192 * @param numOfWords number of words to display in the column
193 */
194 public void setMaxWords(int numOfWords)
195 {
196 this.maxWords = numOfWords;
197 }
198
199 /**
200 * Should null be displayed?
201 * @return true null will be displayed in cell content
202 */
203 public boolean getShowNulls()
204 {
205 return this.showNulls;
206 }
207
208 /**
209 * Enable or disable displaying of null values.
210 * @param outputNulls boolean true if null should be displayed
211 */
212 public void setShowNulls(boolean outputNulls)
213 {
214 this.showNulls = outputNulls;
215 }
216
217 /**
218 * Getter for the name of the property to look up in the bean.
219 * @return String name of the property to look up in the bean
220 */
221 public String getBeanPropertyName()
222 {
223 return this.beanPropertyName;
224 }
225
226 /**
227 * Setter for the name of the property to look up in the bean.
228 * @param propertyName - name of the property to look up in the bean
229 */
230 public void setBeanPropertyName(String propertyName)
231 {
232 this.beanPropertyName = propertyName;
233 }
234
235 /**
236 * Is the column already sorted?
237 * @return true if the column already sorted
238 */
239 public boolean isAlreadySorted()
240 {
241 return this.alreadySorted;
242 }
243
244 /**
245 * Setter for the sorted property (the column is actually sorted).
246 */
247 public void setAlreadySorted()
248 {
249 this.alreadySorted = true;
250 }
251
252 /**
253 * Getter for the column number.
254 * @return int column number
255 */
256 public int getColumnNumber()
257 {
258 return this.columnNumber;
259 }
260
261 /**
262 * Setter for the column number.
263 * @param number - int column number
264 */
265 public void setColumnNumber(int number)
266 {
267 this.columnNumber = number;
268 }
269
270 /**
271 * Returns the columnDecorator object for this column.
272 * @return DisplaytagColumnDecorator
273 */
274 public DisplaytagColumnDecorator[] getColumnDecorators()
275 {
276 return this.columnDecorators != null ? this.columnDecorators : new DisplaytagColumnDecorator[0];
277 }
278
279 /**
280 * Sets the columnDecorator object for this column.
281 * @param decorator - the DisplaytagColumnDecorator
282 */
283 public void setColumnDecorators(DisplaytagColumnDecorator[] decorator)
284 {
285 this.columnDecorators = decorator;
286 }
287
288 /**
289 * Is the column sortable?
290 * @return true if the column is sortable
291 */
292 public boolean getSortable()
293 {
294 return this.sortable;
295 }
296
297 /**
298 * is the column sortable?
299 * @param isSortable - true if the column can be sorted
300 */
301 public void setSortable(boolean isSortable)
302 {
303 this.sortable = isSortable;
304 }
305
306 /**
307 * Get name given to server for sorting this column
308 * @return name given to server for sorting this column
309 */
310 public String getSortName()
311 {
312 return sortName;
313 }
314
315 /**
316 * Set name given to server for sorting this column
317 * @param sortName name given to server for sorting this column
318 */
319 public void setSortName(String sortName)
320 {
321 this.sortName = sortName;
322 }
323
324 /**
325 * Gets the column title.
326 * @return the column title. If no title is specified the capitalized bean property name is returned
327 */
328 public String getTitle()
329 {
330 if (this.title != null)
331 {
332 return this.title;
333 }
334 else if (this.beanPropertyName != null)
335 {
336 return StringUtils.capitalize(this.beanPropertyName);
337 }
338
339 return TagConstants.EMPTY_STRING;
340 }
341
342 /**
343 * Setter for the column title.
344 * @param value - the column title
345 */
346 public void setTitle(String value)
347 {
348 this.title = value;
349 }
350
351 /**
352 * Returns the HtmlAttributeMap containg all the html attributes for the <strong>td </strong> tags.
353 * @return HtmlAttributeMap with td attributes
354 */
355 public HtmlAttributeMap getHtmlAttributes()
356 {
357 return this.htmlAttributes;
358 }
359
360 /**
361 * Sets the HtmlAttributeMap containg all the html attributes for the <strong>td </strong> tags.
362 * @param attributes HtmlAttributeMap
363 */
364 public void setHtmlAttributes(HtmlAttributeMap attributes)
365 {
366 this.htmlAttributes = attributes;
367 }
368
369 /**
370 * returns the HtmlAttributeMap containg all the html attributes for the <strong>th </strong> tag.
371 * @return HtmlAttributeMap with th attributes
372 */
373 public HtmlAttributeMap getHeaderAttributes()
374 {
375 return this.headerAttributes;
376 }
377
378 /**
379 * Sets the HtmlAttributeMap containg all the html attributes for the <strong>th </strong> tag.
380 * @param attributes HtmlAttributeMap
381 */
382 public void setHeaderAttributes(HtmlAttributeMap attributes)
383 {
384 this.headerAttributes = attributes;
385 }
386
387 /**
388 * Adds a css class to the html "class" attribute.
389 * @param cssClass String
390 */
391 public void addHeaderClass(String cssClass)
392 {
393 // null safe
394 if (StringUtils.isBlank(cssClass))
395 {
396 return;
397 }
398
399 // if headerAttributes has not been set, instantiates a new map
400 if (headerAttributes == null)
401 {
402 headerAttributes = new HtmlAttributeMap();
403 }
404
405 Object classAttributes = this.headerAttributes.get(TagConstants.ATTRIBUTE_CLASS);
406
407 // handle multiple values
408 if (classAttributes == null)
409 {
410 this.headerAttributes.put(TagConstants.ATTRIBUTE_CLASS, new MultipleHtmlAttribute(cssClass));
411 }
412 else
413 {
414 ((MultipleHtmlAttribute) classAttributes).addAttributeValue(cssClass);
415 }
416 }
417
418 /**
419 * return the open tag for a column header (th).
420 * @return String <th> tag with attributes
421 */
422 public String getHeaderOpenTag()
423 {
424 return HtmlTagUtil.createOpenTagString(TagConstants.TAGNAME_COLUMN_HEADER, this.headerAttributes);
425 }
426
427 /**
428 * return the closing tag for a cell (td).
429 * @return String </td>
430 */
431 public String getCloseTag()
432 {
433 return TagConstants.TAG_OPENCLOSING + TagConstants.TAGNAME_COLUMN + TagConstants.TAG_CLOSE;
434 }
435
436 /**
437 * return the closing tag for a column header (th).
438 * @return String </th>
439 */
440 public String getHeaderCloseTag()
441 {
442 return TagConstants.TAG_OPENCLOSING + TagConstants.TAGNAME_COLUMN_HEADER + TagConstants.TAG_CLOSE;
443 }
444
445 /**
446 * Setter for the href to be used for dinamic links in cells.
447 * @param baseHref base href for links
448 */
449 public void setHref(Href baseHref)
450 {
451 this.href = baseHref;
452 }
453
454 /**
455 * Getter for the href to be used for dinamic links in cells.
456 * @return Href base href for links
457 */
458 public Href getHref()
459 {
460 return this.href;
461 }
462
463 /**
464 * Setter for the name of the param to add to links.
465 * @param name name of the param
466 */
467 public void setParamName(String name)
468 {
469 this.paramName = name;
470 }
471
472 /**
473 * Getter for the name of the param to add to links.
474 * @return String name of the param
475 */
476 public String getParamName()
477 {
478 return this.paramName;
479 }
480
481 /**
482 * Setter for the name of the property to look up in bean to get the param value for links.
483 * @param property name of the property to look up in bean to get the param value for links
484 */
485 public void setParamProperty(String property)
486 {
487 this.paramProperty = property;
488 }
489
490 /**
491 * Getter for the name of the property to look up in bean to get the param value for links.
492 * @return String name of the property to look up in bean to get the param value for links
493 */
494 public String getParamProperty()
495 {
496 return this.paramProperty;
497 }
498
499 /**
500 * Getter for the name of the property in the bean which will be used for sorting.
501 * @return String name of the property in the bean which will be used for sorting
502 */
503 public String getSortProperty()
504 {
505 return this.sortPropertyName;
506 }
507
508 /**
509 * Setter for the name of the property in the bean which will be used for sorting.
510 * @param propertyName - name of the property in the bean which will be used for sorting
511 */
512 public void setSortProperty(String propertyName)
513 {
514 this.sortPropertyName = propertyName;
515 }
516
517 /**
518 * Sets the default sort order for this column
519 * @return default order
520 */
521 public SortOrderEnum getDefaultSortOrder()
522 {
523 return this.defaultSortOrder;
524 }
525
526 /**
527 * Gets the default sort order for this column
528 * @param order default order
529 */
530 public void setDefaultSortOrder(SortOrderEnum order)
531 {
532 this.defaultSortOrder = order;
533 }
534
535 /**
536 * @see java.lang.Object#toString()
537 */
538 public String toString()
539 {
540 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) //
541 .append("columnNumber", this.columnNumber) //$NON-NLS-1$
542 .append("title", this.title) //$NON-NLS-1$
543 .append("beanPropertyName", this.beanPropertyName) //$NON-NLS-1$
544 .toString();
545 }
546
547 /**
548 * Set the column comparator.
549 * @param columnComparator the value
550 */
551 public void setComparator(Comparator columnComparator)
552 {
553 this.comparator = columnComparator;
554 }
555
556 /**
557 * Get the comparator for sorting this column.
558 * @return the comparator
559 */
560 public Comparator getComparator()
561 {
562 return this.comparator;
563 }
564
565 /**
566 * Will we be keeping a total for this column?
567 * @return true if we are totaling
568 */
569 public boolean isTotaled()
570 {
571 return totaled;
572 }
573
574 /**
575 * Setter for totaled.
576 * @param isTotaled the value
577 */
578 public void setTotaled(boolean isTotaled)
579 {
580 this.totaled = isTotaled;
581 }
582
583 /**
584 * Add the value of this parameter to the column total. The param will be converted to a number via a property
585 * Converter.
586 * @param value the value
587 * @see Converter#convert(Class, Object)
588 */
589 private void addToTotal(Object value)
590 {
591 if (value != null && value instanceof Number)
592 {
593 this.total = this.total + ((Number) value).doubleValue();
594 }
595 }
596
597 /**
598 * Get the current total.
599 * @return the current total.
600 */
601 public double getTotal()
602 {
603 return this.total;
604 }
605
606 /**
607 * Add a new cell to this column.
608 * @param column the value
609 */
610 public void addCell(Column column)
611 {
612 // Not actually going to hold a reference to the added cell - we just need access for the totals
613 if (this.totaled)
614 {
615 try
616 {
617 Object val = column.getValue(false);
618 addToTotal(val);
619 }
620 catch (ObjectLookupException e)
621 {
622 throw new RuntimeException(e);
623 }
624 catch (DecoratorException e)
625 {
626 throw new RuntimeException(e);
627 }
628 }
629 }
630
631 }