/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2014 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.wicket;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.OddEvenItem;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.geoserver.web.data.layergroup.LayerGroupEntry;
import org.geoserver.web.wicket.GeoServerDataProvider.Property;
import org.geoserver.web.wicket.GeoServerDataProvider.PropertyPlaceholder;
import wicketdnd.DragSource;
import wicketdnd.DropTarget;
import wicketdnd.Location;
import wicketdnd.Operation;
import wicketdnd.Transfer;
import wicketdnd.theme.WebTheme;
/**
* Base class for tables that have up/down modifiers
*
* @author Andrea Aime - GeoSolutions
*
* @param <T>
*/
public abstract class ReorderableTablePanel<T> extends GeoServerTablePanel<T> {
private static final long serialVersionUID = -6732973402966999112L;
static class ReorderableDataProvider<T> extends GeoServerDataProvider<T> {
private static final long serialVersionUID = -5792726233183939109L;
private List<T> items;
private List<org.geoserver.web.wicket.GeoServerDataProvider.Property<T>> properties;
@SuppressWarnings("unchecked")
public ReorderableDataProvider(List<T> items, List<Property<T>> properties) {
this.items = items;
this.properties = new ArrayList<Property<T>>(properties);
this.properties.add(0, (Property<T>) POSITION);
this.properties.add(0, (Property<T>) RENDERING_ORDER);
}
@Override
protected List<Property<T>> getProperties() {
return properties;
}
@Override
protected List<T> getItems() {
return items;
}
}
/**
* Cannot declare these non static, because they would be initialized too late, and as static,
* they cannot have the right type argument
*/
static Property<?> POSITION = new PropertyPlaceholder<Object>("position");
static Property<?> RENDERING_ORDER = new PropertyPlaceholder<Object>("order");
@SuppressWarnings("serial")
public ReorderableTablePanel(String id, List<T> items, List<Property<T>> properties) {
super(id, new ReorderableDataProvider<T>(items, properties));
this.setOutputMarkupId(true);
this.add(new WebTheme());
this.add(new DragSource(Operation.MOVE).drag("tr"));
this.add(new DropTarget(Operation.MOVE) {
public void onDrop(AjaxRequestTarget target, Transfer transfer, Location location) {
if (location == null || !(location.getComponent().getDefaultModel().getObject() instanceof LayerGroupEntry)) {
return;
}
T movedItem = transfer.getData();
T targetItem = (T) location.getComponent().getDefaultModel().getObject();
if (movedItem.equals(targetItem)) {
return;
}
items.remove(movedItem);
int idx = items.indexOf(targetItem);
if(idx < (items.size() - 1)) {
items.add(idx, movedItem);
} else {
items.add(movedItem);
}
target.add(ReorderableTablePanel.this);
}
}.dropCenter("tr"));
}
@Override
protected void buildRowListView(GeoServerDataProvider<T> dataProvider, Item<T> item, IModel<T> itemModel) {
// create one component per viewable property
ListView<Property<T>> items = new ListView<Property<T>>("itemProperties", dataProvider.getVisibleProperties()) {
private static final long serialVersionUID = -7089826211241039856L;
@Override
protected void populateItem(ListItem<Property<T>> item) {
Property<T> property = item.getModelObject();
Component component = null;
if (property == POSITION) {
ParamResourceModel upTitle = new ParamResourceModel("moveToTop", this);
ParamResourceModel downTitle = new ParamResourceModel("moveToBottom", this);
component = new UpDownPanel<T>("component", (T) itemModel.getObject(),
dataProvider.getItems(), ReorderableTablePanel.this, upTitle, downTitle);
} else if (property == RENDERING_ORDER) {
component = new Label("component", new Model<String>());
} else {
component = getComponentForProperty("component", itemModel, property);
}
if (component == null) {
// show a plain label if the the subclass did not create any component
component = new Label("component", property.getModel(itemModel));
} else if (!"component".equals(component.getId())) {
// add some checks for the id, the error message
// that wicket returns in case of mismatch is not
// that helpful
throw new IllegalArgumentException("getComponentForProperty asked "
+ "to build a component " + "with id = 'component' " + "for property '"
+ property.getName() + "', but got '" + component.getId() + "' instead");
}
item.add(component);
onPopulateItem(property, item);
}
};
items.setReuseItems(true);
item.add(items);
this.setOutputMarkupId(true);
}
@Override
protected void onPopulateItem(Property<T> property, ListItem<Property<T>> item) {
if (property == RENDERING_ORDER) {
Label label = (Label) item.get(0);
@SuppressWarnings("unchecked")
OddEvenItem<T> rowContainer = (OddEvenItem<T>) item.getParent().getParent();
label.setDefaultModel(new Model<Integer>(rowContainer.getIndex() + 1));
item.add(new Behavior() {
private static final long serialVersionUID = 8429550827543813897L;
@Override
public void onComponentTag(Component component, ComponentTag tag) {
tag.put("style", "width:1%");
}
});
}
};
}