1 package com.panogenesis.webapp.taglib;
2
3 import java.io.IOException;
4
5 import java.text.Collator;
6
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Locale;
13
14 import javax.servlet.jsp.JspException;
15 import javax.servlet.jsp.tagext.TagSupport;
16
17 import com.panogenesis.model.LabelValue;
18
19 import org.displaytag.tags.el.ExpressionEvaluator;
20
21 /***
22 * Tag for creating multiple <select> options for displaying a list of
23 * country names.
24 *
25 * <p>
26 * <b>NOTE</b> - This tag requires a Java2 (JDK 1.2 or later) platform.
27 * </p>
28 *
29 * @author Jens Fischer, Matt Raible
30 * @version $Revision: 1.1 $ $Date: 2004/09/29 10:31:35 $
31 *
32 * @jsp.tag name="country" bodycontent="empty"
33 */
34 public class CountryTag extends TagSupport {
35 private static final String COUNTRIES =
36 CountryTag.class.getName() + ".COUNTRIES";
37 private String name;
38 private String prompt;
39 private String scope;
40 private String selected;
41 private String style;
42 private String styleClass;
43
44 /***
45 * @param name The name to set.
46 *
47 * @jsp.attribute required="false" rtexprvalue="true"
48 */
49 public void setName(String name) {
50 this.name = name;
51 }
52
53 /***
54 * @param prompt The prompt to set.
55 * @jsp.attribute required="false" rtexprvalue="true"
56 */
57 public void setPrompt(String prompt) {
58 this.prompt = prompt;
59 }
60
61 /***
62 * @param selected The selected option.
63 * @jsp.attribute required="false" rtexprvalue="true"
64 */
65 public void setDefault(String selected) {
66 this.selected = selected;
67 }
68
69 /***
70 * Property used to simply stuff the list of countries into a
71 * specified scope.
72 *
73 * @param scope
74 *
75 * @jsp.attribute required="false" rtexprvalue="true"
76 */
77 public void setToScope(String scope) {
78 this.scope = scope;
79 }
80
81 /***
82 * Setter included for XDoclet TLD generation.
83 *
84 * @param style
85 *
86 * @jsp.attribute required="false" rtexprvalue="true"
87 */
88 public void setStyle(String style) {
89 this.style = style;
90 }
91
92 /***
93 * Setter included for XDoclet TLD generation.
94 *
95 * @param styleClass
96 *
97 * @jsp.attribute required="false" rtexprvalue="true"
98 */
99 public void setStyleClass(String styleClass) {
100 this.styleClass = styleClass;
101 }
102
103 /***
104 * Process the start of this tag.
105 *
106 * @return
107 *
108 * @exception JspException if a JSP exception has occurred
109 *
110 * @see javax.servlet.jsp.tagext.Tag#doStartTag()
111 */
112 public int doStartTag() throws JspException {
113 ExpressionEvaluator eval = new ExpressionEvaluator(this, pageContext);
114
115 if (selected != null) {
116 selected = eval.evalString("default", selected);
117 }
118
119 Locale userLocale = pageContext.getRequest().getLocale();
120 List countries = this.buildCountryList(userLocale);
121
122 if (scope != null) {
123 if (scope.equals("page")) {
124 pageContext.setAttribute(name, countries);
125 } else if (scope.equals("request")) {
126 pageContext.getRequest().setAttribute(name, countries);
127 } else if (scope.equals("session")) {
128 pageContext.getSession().setAttribute(name, countries);
129 } else if (scope.equals("application")) {
130 pageContext.getServletContext().setAttribute(name, countries);
131 } else {
132 throw new JspException("Attribute 'scope' must be: page, request, session or application");
133 }
134 } else {
135 StringBuffer sb = new StringBuffer();
136 sb.append("<select name=\"" + name + "\" id=\"" + name + "\">\n");
137
138 if (prompt != null) {
139 sb.append(" <option value=\"\" selected=\"selected\">");
140 sb.append(eval.evalString("prompt", prompt) + "</option>\n");
141 }
142
143 for (Iterator i = countries.iterator(); i.hasNext();) {
144 LabelValue country = (LabelValue) i.next();
145 sb.append(" <option value=\"" + country.getValue() + "\"");
146
147 if ((selected != null) && selected.equals(country.getValue())) {
148 sb.append(" selected=\"selected\"");
149 }
150
151 sb.append(">" + country.getLabel() + "</option>\n");
152 }
153
154 sb.append("</select>");
155
156 try {
157 pageContext.getOut().write(sb.toString());
158 } catch (IOException io) {
159 throw new JspException(io);
160 }
161 }
162
163 return super.doStartTag();
164 }
165
166 /***
167 * Release aquired resources to enable tag reusage.
168 *
169 * @see javax.servlet.jsp.tagext.Tag#release()
170 */
171 public void release() {
172 super.release();
173 }
174
175 /***
176 * Build a List of LabelValues for all the available countries. Uses
177 * the two letter uppercase ISO name of the country as the value and the
178 * localized country name as the label.
179 *
180 * @param locale The Locale used to localize the country names.
181 *
182 * @return List of LabelValues for all available countries.
183 */
184 protected List buildCountryList(Locale locale) {
185 final String EMPTY = "";
186 final Locale[] available = Locale.getAvailableLocales();
187
188 List countries = new ArrayList();
189
190 for (int i = 0; i < available.length; i++) {
191 final String iso = available[i].getCountry();
192 final String name = available[i].getDisplayCountry(locale);
193
194 if (!EMPTY.equals(iso) && !EMPTY.equals(name)) {
195 LabelValue country = new LabelValue(name, iso);
196
197 if (!countries.contains(country)) {
198 countries.add(new LabelValue(name, iso));
199 }
200 }
201 }
202
203 Collections.sort(countries, new LabelValueComparator(locale));
204
205 return countries;
206 }
207
208 /***
209 * Class to compare LabelValues using their labels with
210 * locale-sensitive behaviour.
211 */
212 public class LabelValueComparator implements Comparator {
213 private Comparator c;
214
215 /***
216 * Creates a new LabelValueComparator object.
217 *
218 * @param locale The Locale used for localized String comparison.
219 */
220 public LabelValueComparator(Locale locale) {
221 c = Collator.getInstance(locale);
222 }
223
224 /***
225 * Compares the localized labels of two LabelValues.
226 *
227 * @param o1 The first LabelValue to compare.
228 * @param o2 The second LabelValue to compare.
229 *
230 * @return The value returned by comparing the localized labels.
231 */
232 public final int compare(Object o1, Object o2) {
233 LabelValue lhs = (LabelValue) o1;
234 LabelValue rhs = (LabelValue) o2;
235
236 return c.compare(lhs.getLabel(), rhs.getLabel());
237 }
238 }
239 }