/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.data.layergroup;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.form.validation.IFormValidator;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
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.validation.IValidatable;
import org.apache.wicket.validation.validator.AbstractValidator;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.data.layer.LayerDetachableModel;
import org.geoserver.web.data.style.StyleDetachableModel;
import org.geoserver.web.publish.LayerConfigurationPanel;
import org.geoserver.web.publish.LayerConfigurationPanelInfo;
import org.geoserver.web.publish.LayerGroupConfigurationPanel;
import org.geoserver.web.publish.LayerGroupConfigurationPanelInfo;
import org.geoserver.web.wicket.EnvelopePanel;
import org.geoserver.web.wicket.GeoServerAjaxFormLink;
import org.geoserver.web.wicket.GeoServerDataProvider;
import org.geoserver.web.wicket.GeoServerDataProvider.BeanProperty;
import org.geoserver.web.wicket.GeoServerDataProvider.Property;
import org.geoserver.web.wicket.GeoServerTablePanel;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geoserver.web.wicket.SimpleAjaxLink;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
* Handles layer group
*/
@SuppressWarnings({ "rawtypes", "unchecked", "serial" })
public abstract class AbstractLayerGroupPage extends GeoServerSecuredPage {
public static final String GROUP = "group";
IModel<LayerGroupInfo> lgModel;
EnvelopePanel envelopePanel;
LayerGroupEntryPanel lgEntryPanel;
String layerGroupId;
/**
* Subclasses must call this method to initialize the UI for this page
* @param layerGroup
*/
protected void initUI(LayerGroupInfo layerGroup) {
lgModel = new LayerGroupDetachableModel( layerGroup );
layerGroupId = layerGroup.getId();
Form form = new Form( "form", new CompoundPropertyModel( lgModel ) );
add(form);
TextField name = new TextField("name");
name.setRequired(true);
name.add(new GroupNameValidator());
form.add(name);
//bounding box
form.add(envelopePanel = new EnvelopePanel( "bounds" )/*.setReadOnly(true)*/);
envelopePanel.setRequired(true);
envelopePanel.setCRSFieldVisible(true);
envelopePanel.setOutputMarkupId( true );
form.add(new GeoServerAjaxFormLink( "generateBounds") {
@Override
public void onClick(AjaxRequestTarget target, Form form) {
// build a layer group with the current contents of the group
LayerGroupInfo lg = getCatalog().getFactory().createLayerGroup();
for ( LayerGroupEntry entry : lgEntryPanel.getEntries() ) {
lg.getLayers().add(entry.getLayer());
lg.getStyles().add(entry.getStyle());
}
try {
// grab the eventually manually inserted
CoordinateReferenceSystem crs = envelopePanel.getCoordinateReferenceSystem();
if ( crs != null ) {
//ensure the bounds calculated in terms of the user specified crs
new CatalogBuilder( getCatalog() ).calculateLayerGroupBounds( lg, crs );
}
else {
//calculate from scratch
new CatalogBuilder( getCatalog() ).calculateLayerGroupBounds( lg );
}
envelopePanel.setModelObject( lg.getBounds() );
target.addComponent( envelopePanel );
}
catch (Exception e) {
throw new WicketRuntimeException( e );
}
}
});
form.add(lgEntryPanel = new LayerGroupEntryPanel( "layers", layerGroup ));
//Add panels contributed through extension point
form.add(extensionPanels());
form.add(saveLink());
form.add(cancelLink());
}
private Component extensionPanels() {
final GeoServerApplication gsapp = getGeoServerApplication();
final List<LayerGroupConfigurationPanelInfo> extensions;
extensions = gsapp.getBeansOfType(LayerGroupConfigurationPanelInfo.class);
Component list;
list = new ListView<LayerGroupConfigurationPanelInfo>("contributedPanels", extensions) {
@Override
protected void populateItem(ListItem<LayerGroupConfigurationPanelInfo> item) {
final LayerGroupConfigurationPanelInfo panelInfo = item.getModelObject();
try {
LayerGroupConfigurationPanel panel;
Class<LayerGroupConfigurationPanel> componentClass;
Constructor<? extends LayerGroupConfigurationPanel> constructor;
componentClass = panelInfo.getComponentClass();
constructor = componentClass.getConstructor(String.class, IModel.class);
panel = constructor.newInstance("content", lgModel);
item.add(panel);
} catch (Exception e) {
throw new WicketRuntimeException(
"Failed to add pluggable layergroup configuration panels", e);
}
}
};
return list;
}
private BookmarkablePageLink cancelLink() {
return new BookmarkablePageLink("cancel", LayerGroupPage.class);
}
private SubmitLink saveLink() {
return new SubmitLink("save"){
@Override
public void onSubmit() {
if(lgEntryPanel.getEntries().size() == 0) {
error((String) new ParamResourceModel("oneLayerMinimum", getPage()).getObject());
return;
}
// update the layer group entries
LayerGroupInfo lg = (LayerGroupInfo) lgModel.getObject();
lg.getLayers().clear();
lg.getStyles().clear();
for ( LayerGroupEntry entry : lgEntryPanel.getEntries() ) {
lg.getLayers().add(entry.getLayer());
lg.getStyles().add(entry.getStyle());
}
AbstractLayerGroupPage.this.onSubmit();
}
};
}
/**
* Subclasses
*/
protected abstract void onSubmit();
abstract static class StyleListPanel extends GeoServerTablePanel<StyleInfo> {
static Property<StyleInfo> NAME =
new BeanProperty<StyleInfo>("name", "name");
public StyleListPanel(String id) {
super(id, new GeoServerDataProvider<StyleInfo>() {
@Override
protected List<StyleInfo> getItems() {
return getCatalog().getStyles();
}
@Override
protected List<Property<StyleInfo>> getProperties() {
return Arrays.asList( NAME );
}
public IModel newModel(Object object) {
return new StyleDetachableModel( (StyleInfo) object );
}
});
getTopPager().setVisible(false);
}
@Override
protected Component getComponentForProperty(String id, IModel itemModel,
Property<StyleInfo> property) {
final StyleInfo style = (StyleInfo) itemModel.getObject();
if ( property == NAME ) {
return new SimpleAjaxLink( id, NAME.getModel( itemModel ) ) {
@Override
public void onClick(AjaxRequestTarget target) {
handleStyle(style, target);
}
};
}
return null;
}
protected abstract void handleStyle( StyleInfo style, AjaxRequestTarget target );
}
abstract static class LayerListPanel extends GeoServerTablePanel<LayerInfo> {
static Property<LayerInfo> NAME =
new BeanProperty<LayerInfo>("name", "name");
static Property<LayerInfo> STORE =
new BeanProperty<LayerInfo>("store", "resource.store.name");
static Property<LayerInfo> WORKSPACE =
new BeanProperty<LayerInfo>("workspace", "resource.store.workspace.name");
LayerListPanel( String id ) {
super( id, new GeoServerDataProvider<LayerInfo>() {
@Override
protected List<LayerInfo> getItems() {
return getCatalog().getLayers();
}
@Override
protected List<Property<LayerInfo>> getProperties() {
return Arrays.asList( NAME, STORE, WORKSPACE );
}
public IModel newModel(Object object) {
return new LayerDetachableModel((LayerInfo)object);
}
});
getTopPager().setVisible(false);
}
@Override
protected Component getComponentForProperty(String id, final IModel itemModel,
Property<LayerInfo> property) {
IModel model = property.getModel( itemModel );
if ( NAME == property ) {
return new SimpleAjaxLink( id, model ) {
@Override
protected void onClick(AjaxRequestTarget target) {
LayerInfo layer = (LayerInfo) itemModel.getObject();
handleLayer( layer, target );
}
};
}
else {
return new Label( id, model );
}
}
protected void handleLayer( LayerInfo layer, AjaxRequestTarget target ) {
}
}
class GroupNameValidator extends AbstractValidator {
@Override
protected void onValidate(IValidatable validatable) {
String name = (String) validatable.getValue();
LayerGroupInfo other = getCatalog().getLayerGroupByName(name);
if(other != null && (layerGroupId == null || !other.getId().equals(layerGroupId))) {
error(validatable, "duplicateGroupNameError", Collections.singletonMap("name", name));
}
}
}
}