1 |
wvengen |
665 |
Index: src/java/org/xhtmlrenderer/simple/extend/form/SelectField.java |
2 |
|
|
=================================================================== |
3 |
|
|
RCS file: /cvs/xhtmlrenderer/src/java/org/xhtmlrenderer/simple/extend/form/SelectField.java,v |
4 |
|
|
retrieving revision 1.4 |
5 |
|
|
diff -u -r1.4 SelectField.java |
6 |
|
|
--- src/java/org/xhtmlrenderer/simple/extend/form/SelectField.java 25 Apr 2009 11:50:34 -0000 1.4 |
7 |
|
|
+++ src/java/org/xhtmlrenderer/simple/extend/form/SelectField.java 28 Jul 2009 15:38:15 -0000 |
8 |
|
|
@@ -19,14 +19,22 @@ |
9 |
|
|
*/ |
10 |
|
|
package org.xhtmlrenderer.simple.extend.form; |
11 |
|
|
|
12 |
|
|
+import java.awt.Component; |
13 |
|
|
+import java.awt.Font; |
14 |
|
|
+import java.awt.event.ItemEvent; |
15 |
|
|
+import java.awt.event.ItemListener; |
16 |
|
|
import java.util.ArrayList; |
17 |
|
|
import java.util.List; |
18 |
|
|
|
19 |
|
|
+import javax.swing.DefaultListCellRenderer; |
20 |
|
|
import javax.swing.JComboBox; |
21 |
|
|
import javax.swing.JComponent; |
22 |
|
|
import javax.swing.JList; |
23 |
|
|
import javax.swing.JScrollPane; |
24 |
|
|
+import javax.swing.ListModel; |
25 |
|
|
import javax.swing.ListSelectionModel; |
26 |
|
|
+import javax.swing.event.ListSelectionEvent; |
27 |
|
|
+import javax.swing.event.ListSelectionListener; |
28 |
|
|
|
29 |
|
|
import org.w3c.dom.Element; |
30 |
|
|
import org.w3c.dom.NodeList; |
31 |
|
|
@@ -44,6 +52,9 @@ |
32 |
|
|
// Either a select list or a drop down/combobox |
33 |
|
|
if (shouldRenderAsList()) { |
34 |
|
|
JList select = new JList(optionList.toArray()); |
35 |
|
|
+ |
36 |
|
|
+ select.setCellRenderer(new CellRenderer()); |
37 |
|
|
+ select.addListSelectionListener(new HeadingItemListener()); |
38 |
|
|
|
39 |
|
|
if (hasAttribute("multiple") && getAttribute("multiple").equalsIgnoreCase("true")) { |
40 |
|
|
select.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); |
41 |
|
|
@@ -69,6 +80,8 @@ |
42 |
|
|
JComboBox select = new JComboBox(optionList.toArray()); |
43 |
|
|
|
44 |
|
|
select.setEditable(false); |
45 |
|
|
+ select.setRenderer(new CellRenderer()); |
46 |
|
|
+ select.addItemListener(new HeadingItemListener()); |
47 |
|
|
|
48 |
|
|
return select; |
49 |
|
|
} |
50 |
|
|
@@ -120,7 +133,9 @@ |
51 |
|
|
String [] submitValues = new String [selectedValues.length]; |
52 |
|
|
|
53 |
|
|
for (int i = 0; i < selectedValues.length; i++) { |
54 |
|
|
- submitValues[i] = ((NameValuePair) selectedValues[i]).getValue(); |
55 |
|
|
+ NameValuePair pair = (NameValuePair) selectedValues[i]; |
56 |
|
|
+ if (pair.getValue()!=null) |
57 |
|
|
+ submitValues[i] = pair.getValue(); |
58 |
|
|
} |
59 |
|
|
|
60 |
|
|
return submitValues; |
61 |
|
|
@@ -129,33 +144,46 @@ |
62 |
|
|
|
63 |
|
|
NameValuePair selectedValue = (NameValuePair) select.getSelectedItem(); |
64 |
|
|
|
65 |
|
|
- if (selectedValue == null) { |
66 |
|
|
- return new String [] {}; |
67 |
|
|
- } else { |
68 |
|
|
- return new String [] { selectedValue.getValue() }; |
69 |
|
|
+ if (selectedValue != null) { |
70 |
|
|
+ if (selectedValue.getValue()!=null) |
71 |
|
|
+ return new String [] { selectedValue.getValue() }; |
72 |
|
|
} |
73 |
|
|
} |
74 |
|
|
+ |
75 |
|
|
+ return new String [] {}; |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
private List createList() { |
79 |
|
|
- List list = new ArrayList(); |
80 |
|
|
- |
81 |
|
|
- NodeList options = getElement().getElementsByTagName("option"); |
82 |
|
|
+ List list = new ArrayList(); |
83 |
|
|
+ addChildren(list, getElement(), 0); |
84 |
|
|
+ return list; |
85 |
|
|
+ } |
86 |
|
|
|
87 |
|
|
- for (int i = 0; i < options.getLength(); i++) { |
88 |
|
|
- Element option = (Element) options.item(i); |
89 |
|
|
- |
90 |
|
|
- String optionText = XhtmlForm.collectText(option); |
91 |
|
|
- String optionValue = optionText; |
92 |
|
|
- |
93 |
|
|
- if (option.hasAttribute("value")) { |
94 |
|
|
- optionValue = option.getAttribute("value"); |
95 |
|
|
+ private void addChildren(List list, Element e, int indent) { |
96 |
|
|
+ NodeList children = e.getChildNodes(); |
97 |
|
|
+ |
98 |
|
|
+ for (int i = 0; i < children.getLength(); i++) { |
99 |
|
|
+ if (!(children.item(i) instanceof Element)) continue; |
100 |
|
|
+ Element child = (Element) children.item(i); |
101 |
|
|
+ |
102 |
|
|
+ if ("option".equals(child.getNodeName())) { |
103 |
|
|
+ // option tag, add it |
104 |
|
|
+ String optionText = XhtmlForm.collectText(child); |
105 |
|
|
+ String optionValue = optionText; |
106 |
|
|
+ |
107 |
|
|
+ if (child.hasAttribute("value")) { |
108 |
|
|
+ optionValue = child.getAttribute("value"); |
109 |
|
|
+ } |
110 |
|
|
+ |
111 |
|
|
+ list.add(new NameValuePair(optionText, optionValue, indent)); |
112 |
|
|
+ |
113 |
|
|
+ } else if ("optgroup".equals(child.getNodeName())) { |
114 |
|
|
+ // optgroup tag, append heading and indent children |
115 |
|
|
+ String titleText = child.getAttribute("label"); |
116 |
|
|
+ list.add(new NameValuePair(titleText, null, indent)); |
117 |
|
|
+ addChildren(list, child, indent+1); |
118 |
|
|
} |
119 |
|
|
- |
120 |
|
|
- list.add(new NameValuePair(optionText, optionValue)); |
121 |
|
|
} |
122 |
|
|
- |
123 |
|
|
- return list; |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
private boolean shouldRenderAsList() { |
127 |
|
|
@@ -177,14 +205,22 @@ |
128 |
|
|
/** |
129 |
|
|
* Provides a simple container for name/value data, such as that used |
130 |
|
|
* by the <option> elements in a <select> list. |
131 |
|
|
+ * <p> |
132 |
|
|
+ * When the value is {@code null}, this pair is used as a heading and |
133 |
|
|
+ * should not be selected by itself. |
134 |
|
|
+ * <p> |
135 |
|
|
+ * The indent property was added to support indentation of items as |
136 |
|
|
+ * children below headings. |
137 |
|
|
*/ |
138 |
|
|
private static class NameValuePair { |
139 |
|
|
private String _name; |
140 |
|
|
private String _value; |
141 |
|
|
+ private int _indent; |
142 |
|
|
|
143 |
|
|
- public NameValuePair(String name, String value) { |
144 |
|
|
+ public NameValuePair(String name, String value, int indent) { |
145 |
|
|
_name = name; |
146 |
|
|
_value = value; |
147 |
|
|
+ _indent = indent; |
148 |
|
|
} |
149 |
|
|
|
150 |
|
|
public String getName() { |
151 |
|
|
@@ -194,10 +230,100 @@ |
152 |
|
|
public String getValue() { |
153 |
|
|
return _value; |
154 |
|
|
} |
155 |
|
|
+ |
156 |
|
|
+ public int getIndent() { |
157 |
|
|
+ return _indent; |
158 |
|
|
+ } |
159 |
|
|
|
160 |
|
|
public String toString() { |
161 |
|
|
- return getName(); |
162 |
|
|
+ String txt = getName(); |
163 |
|
|
+ for (int i = 0; i < getIndent(); i++) |
164 |
|
|
+ txt = " " + txt; |
165 |
|
|
+ return txt; |
166 |
|
|
} |
167 |
|
|
} |
168 |
|
|
+ |
169 |
|
|
+ /** |
170 |
|
|
+ * Renderer for ordinary items and headings in a List. |
171 |
|
|
+ */ |
172 |
|
|
+ private static class CellRenderer extends DefaultListCellRenderer { |
173 |
|
|
+ public Component getListCellRendererComponent(JList list, Object value, |
174 |
|
|
+ int index, boolean isSelected, boolean cellHasFocus) { |
175 |
|
|
+ NameValuePair pair = (NameValuePair)value; |
176 |
|
|
+ |
177 |
|
|
+ if (pair!=null && pair.getValue()==null) { |
178 |
|
|
+ // render as heading as such |
179 |
|
|
+ super.getListCellRendererComponent(list, value, index, false, false); |
180 |
|
|
+ Font fold = getFont(); |
181 |
|
|
+ Font fnew = new Font(fold.getName(), Font.BOLD | Font.ITALIC, fold.getSize()); |
182 |
|
|
+ setFont(fnew); |
183 |
|
|
+ } else { |
184 |
|
|
+ // other items as usuall |
185 |
|
|
+ super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
186 |
|
|
+ } |
187 |
|
|
+ |
188 |
|
|
+ return this; |
189 |
|
|
+ } |
190 |
|
|
+ } |
191 |
|
|
+ |
192 |
|
|
+ /** |
193 |
|
|
+ * Helper class that makes headings inside a list unselectable |
194 |
|
|
+ * <p> |
195 |
|
|
+ * This is an {@linkplain ItemListener} for comboboxes, and a |
196 |
|
|
+ * {@linkplain ListSelectionListener} for lists. |
197 |
|
|
+ */ |
198 |
|
|
+ private static class HeadingItemListener implements ItemListener, ListSelectionListener { |
199 |
|
|
+ |
200 |
|
|
+ private Object oldSelection = null; |
201 |
|
|
+ private int[] oldSelections = new int[0]; |
202 |
|
|
+ |
203 |
|
|
+ public void itemStateChanged(ItemEvent e) { |
204 |
|
|
+ if (e.getStateChange() != ItemEvent.SELECTED) |
205 |
|
|
+ return; |
206 |
|
|
+ // only for comboboxes |
207 |
|
|
+ if (! (e.getSource() instanceof JComboBox) ) |
208 |
|
|
+ return; |
209 |
|
|
+ JComboBox combo = (JComboBox)e.getSource(); |
210 |
|
|
+ |
211 |
|
|
+ if (((NameValuePair)e.getItem()).getValue() == null) { |
212 |
|
|
+ // header selected: revert to old selection |
213 |
|
|
+ combo.setSelectedItem(oldSelection); |
214 |
|
|
+ } else { |
215 |
|
|
+ // store old selection |
216 |
|
|
+ oldSelection = e.getItem(); |
217 |
|
|
+ } |
218 |
|
|
+ } |
219 |
|
|
|
220 |
|
|
+ public void valueChanged(ListSelectionEvent e) { |
221 |
|
|
+ // only for lists |
222 |
|
|
+ if (! (e.getSource() instanceof JList) ) |
223 |
|
|
+ return; |
224 |
|
|
+ JList list = (JList)e.getSource(); |
225 |
|
|
+ ListModel model = list.getModel(); |
226 |
|
|
+ |
227 |
|
|
+ // deselect all headings |
228 |
|
|
+ for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) { |
229 |
|
|
+ if (!list.isSelectedIndex(i)) continue; |
230 |
|
|
+ NameValuePair pair = (NameValuePair) model.getElementAt(i); |
231 |
|
|
+ if ( pair!=null && pair.getValue() == null) { |
232 |
|
|
+ // We have a heading, remove it. As this handler is called |
233 |
|
|
+ // as a result of the resulting removal and we do process |
234 |
|
|
+ // the events while the value is adjusting, we don't need |
235 |
|
|
+ // to process any other headings here. |
236 |
|
|
+ // BUT if there'll be no selection anymore because by selecting |
237 |
|
|
+ // this one the old selection was cleared, restore the old |
238 |
|
|
+ // selection. |
239 |
|
|
+ if (list.getSelectedIndices().length==1) |
240 |
|
|
+ list.setSelectedIndices(oldSelections); |
241 |
|
|
+ else |
242 |
|
|
+ list.removeSelectionInterval(i, i); |
243 |
|
|
+ return; |
244 |
|
|
+ } |
245 |
|
|
+ } |
246 |
|
|
+ |
247 |
|
|
+ // if final selection: store it |
248 |
|
|
+ if (!e.getValueIsAdjusting()) |
249 |
|
|
+ oldSelections = list.getSelectedIndices(); |
250 |
|
|
+ } |
251 |
|
|
+ } |
252 |
|
|
} |