/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.web.wicket.property; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.FormComponentPanel; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.util.ListModel; import org.apache.wicket.validation.ValidationError; import org.springframework.util.StringUtils; /** * Form component panel for editing {@link Properties} property. * * @author Justin Deoliveira, OpenGeo */ public class PropertyEditorFormComponent extends FormComponentPanel<Properties> { private static final long serialVersionUID = -1960584178014140068L; ListView<Tuple> listView; List<Tuple> invalidTuples=null; public PropertyEditorFormComponent(String id) { super(id); init(); } public PropertyEditorFormComponent(String id, IModel<Properties> model) { super(id, model); init(); } void init() { final WebMarkupContainer container = new WebMarkupContainer("container"); container.setOutputMarkupId(true); add(container); listView = new ListView<Tuple>("list") { private static final long serialVersionUID = -7250612551499360015L; @Override protected void populateItem(ListItem<Tuple> item) { item.setModel(new CompoundPropertyModel<Tuple>(item.getModelObject())); item.add(new TextField<String>("key").add(new AjaxFormComponentUpdatingBehavior("blur"){ private static final long serialVersionUID = 5416373713193788662L; @Override protected void onUpdate(AjaxRequestTarget target) { } })); item.add(new TextField<String>("value").add(new AjaxFormComponentUpdatingBehavior("blur") { private static final long serialVersionUID = -8679502120189597358L; @Override protected void onUpdate(AjaxRequestTarget target) { } })); item.add(new AjaxLink<Tuple>("remove", item.getModel()) { private static final long serialVersionUID = 3201264868229144613L; @Override public void onClick(AjaxRequestTarget target) { List<Tuple> l = listView.getModelObject(); l.remove(getModelObject()); target.add(container); } }); } }; //listView.setReuseItems(true); container.add(listView); add(new AjaxLink<Void>("add") { private static final long serialVersionUID = 4741595573705562351L; @Override public void onClick(AjaxRequestTarget target) { listView.getModelObject().add(new Tuple()); target.add(container); } }); } List<Tuple> tuples() { if (invalidTuples!=null) return invalidTuples; Properties props = getModelObject(); if (props == null) { props = new Properties(); } List<Tuple> tuples = new ArrayList<Tuple>(); for (Map.Entry<Object, Object> e : props.entrySet()) { tuples.add(new Tuple((String)e.getKey(), (String)e.getValue())); } Collections.sort(tuples); return tuples; } @Override protected void onBeforeRender() { listView.setModel(new ListModel<Tuple>(tuples())); super.onBeforeRender(); } @Override public void convertInput() { for (Iterator<?> it = listView.iterator(); it.hasNext();) { ListItem<?> item = (ListItem<?>) it.next(); ((FormComponent<?>)item.get("key")).updateModel(); ((FormComponent<?>)item.get("value")).updateModel(); } Properties props = getModelObject(); if (props == null) { props = new Properties(); } props.clear(); for (Tuple t : listView.getModelObject()) { props.put(t.getKey(), t.getValue()); } setConvertedInput(props); } @Override public void validate() { invalidTuples=null; for (Tuple t : listView.getModelObject()) { if (StringUtils.hasLength(t.getKey())== false) { invalidTuples=listView.getModelObject(); error(new ValidationError("KeyRequired").addKey("KeyRequired")); return; } if (StringUtils.hasLength(t.getValue())== false) { invalidTuples=listView.getModelObject(); error(new ValidationError("ValueRequired").addKey("ValueRequired")); return; } } super.validate(); } static class Tuple implements Serializable, Comparable<Tuple> { private static final long serialVersionUID = 1L; private String key; private String value; public Tuple() { } public Tuple(String key, String value) { this.key = key; this.value = value; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public int compareTo(Tuple o) { return key != null ? key.compareTo(o.key) : o.key == null ? 0 : -1; } } }