1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.ui.commons.markup.html.form;
20
21 import com.googlecode.wicket.jquery.core.Options;
22 import com.googlecode.wicket.jquery.ui.JQueryUIBehavior;
23 import com.googlecode.wicket.jquery.ui.form.spinner.AjaxSpinner;
24 import com.googlecode.wicket.jquery.ui.form.spinner.SpinnerAdapter;
25 import com.googlecode.wicket.jquery.ui.form.spinner.SpinnerBehavior;
26 import java.io.Serializable;
27 import java.util.List;
28 import java.util.Optional;
29 import java.util.function.Predicate;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.lang3.math.NumberUtils;
32 import org.apache.syncope.client.ui.commons.Constants;
33 import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
34 import org.apache.syncope.common.lib.Attr;
35 import org.apache.syncope.common.lib.Attributable;
36 import org.apache.wicket.ajax.AjaxRequestTarget;
37 import org.apache.wicket.markup.html.list.ListItem;
38 import org.apache.wicket.model.IModel;
39 import org.apache.wicket.model.Model;
40 import org.apache.wicket.model.ResourceModel;
41
42 public final class AjaxSpinnerFieldPanel<T extends Number> extends FieldPanel<T> {
43
44 private static final long serialVersionUID = 6413819574530703577L;
45
46 private final Class<T> reference;
47
48 private final IModel<T> model;
49
50 private final Options options;
51
52 private final boolean convertValuesToString;
53
54 private SpinnerBehavior behavior;
55
56 private AjaxSpinnerFieldPanel(
57 final String id,
58 final String name,
59 final Class<T> reference,
60 final IModel<T> model,
61 final Options options,
62 final boolean enableOnChange,
63 final boolean convertValuesToString) {
64
65 super(id, name, model);
66
67 field = new AjaxSpinner<>("spinner", model, options, reference) {
68
69 private static final long serialVersionUID = -3624755213720060594L;
70
71 @Override
72 public JQueryUIBehavior newWidgetBehavior(final String selector) {
73 behavior = new SpinnerBehavior(selector, new SpinnerAdapter());
74 behavior.setOptions(options);
75 return behavior;
76 }
77 };
78
79 if (enableOnChange && !isReadOnly()) {
80 field.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
81
82 private static final long serialVersionUID = -1107858522700306810L;
83
84 @Override
85 protected void onUpdate(final AjaxRequestTarget target) {
86
87 }
88 });
89 }
90
91 add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true));
92
93 this.name = name;
94 this.model = model;
95 this.reference = reference;
96 this.options = options;
97 this.convertValuesToString = convertValuesToString;
98 }
99
100 @Override
101 public AjaxSpinnerFieldPanel<T> setNewModel(final List<Serializable> list) {
102 setNewModel(new Model<>() {
103
104 private static final long serialVersionUID = 527651414610325237L;
105
106 @Override
107 public T getObject() {
108 T value = null;
109
110 if (list != null && !list.isEmpty()
111 && list.get(0) != null && StringUtils.isNotBlank(list.get(0).toString())) {
112
113 value = reference.equals(Integer.class)
114 ? reference.cast(NumberUtils.toInt(list.get(0).toString()))
115 : reference.equals(Long.class)
116 ? reference.cast(NumberUtils.toLong(list.get(0).toString()))
117 : reference.equals(Short.class)
118 ? reference.cast(NumberUtils.toShort(list.get(0).toString()))
119 : reference.equals(Float.class)
120 ? reference.cast(NumberUtils.toFloat(list.get(0).toString()))
121 : reference.equals(byte.class)
122 ? reference.cast(NumberUtils.toByte(list.get(0).toString()))
123 : reference.cast(NumberUtils.toDouble(list.get(0).toString()));
124 }
125
126 return value;
127 }
128
129 @Override
130 public void setObject(final T object) {
131 list.clear();
132 Optional.ofNullable(object).ifPresent(v -> list.add(convertValuesToString ? v.toString() : v));
133 }
134 });
135
136 return this;
137 }
138
139 @SuppressWarnings("rawtypes")
140 @Override
141 public AjaxSpinnerFieldPanel<T> setNewModel(final ListItem item) {
142 field.setModel(new Model<>() {
143
144 private static final long serialVersionUID = 6799404673615637845L;
145
146 @Override
147 public T getObject() {
148 T number = null;
149
150 final Object obj = item.getModelObject();
151
152 if (obj != null && !obj.toString().isEmpty()) {
153 if (obj instanceof String) {
154 try {
155 number = reference.equals(Integer.class)
156 ? reference.cast(Integer.valueOf((String) obj))
157 : reference.equals(Long.class)
158 ? reference.cast(Long.valueOf((String) obj))
159 : reference.equals(Short.class)
160 ? reference.cast(Short.valueOf((String) obj))
161 : reference.equals(Float.class)
162 ? reference.cast(Float.valueOf((String) obj))
163 : reference.equals(byte.class)
164 ? reference.cast(Byte.valueOf((String) obj))
165 : reference.cast(Double.valueOf((String) obj));
166 } catch (NumberFormatException e) {
167 LOG.error("While attempting to parse {}", obj, e);
168 }
169 } else if (obj instanceof Number) {
170 number = reference.equals(Integer.class)
171 ? reference.cast(((Number) obj).intValue())
172 : reference.equals(Long.class)
173 ? reference.cast(((Number) obj).longValue())
174 : reference.equals(Short.class)
175 ? reference.cast(((Number) obj).shortValue())
176 : reference.equals(Float.class)
177 ? reference.cast(((Number) obj).floatValue())
178 : reference.equals(byte.class)
179 ? reference.cast(((Number) obj).byteValue())
180 : reference.cast(((Number) obj).doubleValue());
181 }
182 }
183
184 return number;
185 }
186
187 @Override
188 @SuppressWarnings("unchecked")
189 public void setObject(final T object) {
190 item.setModelObject(Optional.ofNullable(object).
191 map(v -> convertValuesToString ? v.toString() : v).
192 orElse(null));
193 }
194 });
195
196 return this;
197 }
198
199 @SuppressWarnings({ "unchecked", "rawtypes" })
200 @Override
201 public FieldPanel<T> setNewModel(final Attributable attributable, final String schema) {
202 field.setModel(new Model() {
203
204 private static final long serialVersionUID = -4214654722524358000L;
205
206 @Override
207 public Serializable getObject() {
208 return attributable.getPlainAttr(schema).map(Attr::getValues).filter(Predicate.not(List::isEmpty)).
209 map(values -> reference.equals(Integer.class)
210 ? reference.cast(NumberUtils.toInt(values.get(0)))
211 : reference.equals(Long.class)
212 ? reference.cast(NumberUtils.toLong(values.get(0)))
213 : reference.equals(Short.class)
214 ? reference.cast(NumberUtils.toShort(values.get(0)))
215 : reference.equals(Float.class)
216 ? reference.cast(NumberUtils.toFloat(values.get(0)))
217 : reference.equals(byte.class)
218 ? reference.cast(NumberUtils.toByte(values.get(0)))
219 : reference.cast(NumberUtils.toDouble(values.get(0)))).
220 orElse(null);
221 }
222
223 @Override
224 public void setObject(final Serializable object) {
225 attributable.getPlainAttr(schema).ifPresent(plainAttr -> {
226 plainAttr.getValues().clear();
227 Optional.ofNullable(object).ifPresent(o -> plainAttr.getValues().add(o.toString()));
228 });
229 }
230 });
231
232 return this;
233 }
234
235 @Override
236 public AjaxSpinnerFieldPanel<T> clone() {
237 AjaxSpinnerFieldPanel<T> panel = new AjaxSpinnerFieldPanel<>(
238 getId(), name, reference, model, options, false, convertValuesToString);
239
240 panel.setRequired(isRequired());
241 panel.setReadOnly(isReadOnly());
242 panel.setTitle(title);
243
244 if (isRequiredLabelAdded) {
245 panel.addRequiredLabel();
246 }
247
248 return panel;
249 }
250
251 @Override
252 public FieldPanel<T> setReadOnly(final boolean readOnly) {
253 super.setReadOnly(readOnly);
254 AjaxSpinner.class.cast(field).setEnabled(!readOnly);
255 options.set("disabled", readOnly);
256 if (behavior != null) {
257 behavior.setOptions(options);
258 }
259 return this;
260 }
261
262 public static class Builder<T extends Number> {
263
264 private final Options options = new Options();
265
266 private boolean enableOnChange = false;
267
268 private boolean convertValuesToString = true;
269
270 public Builder<T> min(final T min) {
271 options.set("min", min);
272 return this;
273 }
274
275 public Builder<T> max(final T max) {
276 options.set("max", max);
277 return this;
278 }
279
280 public Builder<T> step(final T step) {
281 options.set("step", step);
282 return this;
283 }
284
285 public Builder<T> enableOnChange() {
286 enableOnChange = true;
287 return this;
288 }
289
290 public Builder<T> convertValuesToString(final boolean convertValuesToString) {
291 this.convertValuesToString = convertValuesToString;
292 return this;
293 }
294
295 public AjaxSpinnerFieldPanel<T> build(
296 final String id,
297 final String name,
298 final Class<T> reference,
299 final IModel<T> model) {
300
301 return new AjaxSpinnerFieldPanel<>(
302 id, name, reference, model, options, enableOnChange, convertValuesToString);
303 }
304 }
305 }