org.geoserver.web.wicket.CRSPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.web.wicket.CRSPanel.java

Source

/* (c) 2014 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;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
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.behavior.IBehavior;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.basic.MultiLineLabel;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponentPanel;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.geotools.referencing.CRS;
import org.geotools.util.logging.Logging;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

/**
 * A form component for a {@link CoordinateReferenceSystem} object.
 * <p>
 * This panel provides the following functionality/information:
 * <ul>
 *   <li>The SRS (epsg code) of the CRS
 *   <li>View the full WKT of the CRS.
 *   <li>A mechanism to guess the SRS (epsg code) from the CRS
 *   <li>A lookup for browsing for a particular CRS 
 * </ul>
 * </p>
 * @author Justin Deoliveira, OpenGeo
 */
@SuppressWarnings("serial")
public class CRSPanel extends FormComponentPanel {
    private static Logger LOGGER = Logging.getLogger(CRSPanel.class);
    private static final long serialVersionUID = -6677103383336166008L;

    private static IBehavior READ_ONLY = new AttributeModifier("readonly", true, new Model("readonly"));

    /** pop-up window for WKT and SRS list */
    protected ModalWindow popupWindow;

    /** srs/epsg code text field */
    protected TextField srsTextField;

    /** find link */
    protected AjaxLink findLink;

    /** wkt label */
    protected Label wktLabel;

    /** the wkt link that contains the wkt label **/
    protected GeoServerAjaxFormLink wktLink;

    /**
     * Constructs the CRS panel.
     * <p>
     * This constructor should be used if the panel is to inherit from a parent model 
     * (ie a CompoundPropertyModel). If no such model is available the CRS will be left 
     * uninitialized. To avoid inheriting from a parent model the constructor {@link #CRSPanel(String, IModel)}
     * should be used, specifying explicitly an uninitialized model. 
     *</p>
     * @param id The component id.
     */
    public CRSPanel(String id) {
        super(id);
        initComponents();
    }

    /**
     * Constructs the CRS panel with an explicit model.
     *
     * @param id The component id.
     * @param model The model, usually a {@link PropertyModel}.
     */
    public CRSPanel(String id, IModel model) {
        super(id, model);
        initComponents();
    }

    /**
     * Constructs the CRS panel specifying the underlying CRS explicitly.
     * <p>
     * When this constructor is used the {@link #getCRS()} method should be used 
     * after the form is submitted to retrieve the final value of the CRS.
     * </p>
     * @param id The component id.
     * @param crs The underlying CRS object.
     */
    public CRSPanel(String id, CoordinateReferenceSystem crs) {
        //JD: while the CoordinateReferenceSystem interface does not implement Serializable
        // all the CRS objects we use do, hence the cast
        super(id, new Model((Serializable) crs));
        initComponents();
        setConvertedInput(crs);
    }

    /*
     * helper for internally creating the panel. 
     */
    void initComponents() {

        popupWindow = new ModalWindow("popup");
        add(popupWindow);

        srsTextField = new TextField("srs", new Model());
        add(srsTextField);
        srsTextField.setOutputMarkupId(true);

        srsTextField.add(new AjaxFormComponentUpdatingBehavior("onblur") {

            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                convertInput();

                CoordinateReferenceSystem crs = (CoordinateReferenceSystem) getConvertedInput();
                if (crs != null) {
                    setModelObject(crs);
                    wktLabel.setDefaultModelObject(crs.getName().toString());
                    wktLink.setEnabled(true);
                } else {
                    wktLabel.setDefaultModelObject(null);
                    wktLink.setEnabled(false);
                }
                target.addComponent(wktLink);

                onSRSUpdated(toSRS(crs), target);
            }
        });

        findLink = new AjaxLink("find") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                popupWindow.setContent(srsListPanel());
                popupWindow.setTitle(new ParamResourceModel("selectSRS", CRSPanel.this));
                popupWindow.show(target);
            }
        };
        add(findLink);

        wktLink = new GeoServerAjaxFormLink("wkt") {
            @Override
            public void onClick(AjaxRequestTarget target, Form form) {
                popupWindow.setInitialHeight(375);
                popupWindow.setInitialWidth(525);
                popupWindow.setContent(new WKTPanel(popupWindow.getContentId(), getCRS()));
                CoordinateReferenceSystem crs = (CoordinateReferenceSystem) CRSPanel.this.getModelObject();
                if (crs != null)
                    popupWindow.setTitle(crs.getName().toString());
                popupWindow.show(target);
            }
        };
        wktLink.setEnabled(getModelObject() != null);
        add(wktLink);

        wktLabel = new Label("wktLabel", new Model());
        wktLink.add(wktLabel);
        wktLabel.setOutputMarkupId(true);
    }

    @Override
    protected void onBeforeRender() {
        CoordinateReferenceSystem crs = (CoordinateReferenceSystem) getModelObject();
        if (crs != null) {
            srsTextField.setModelObject(toSRS(crs));
            wktLabel.setDefaultModelObject(crs.getName().toString());
        } else {
            wktLabel.setDefaultModelObject(null);
            wktLink.setEnabled(false);
        }

        super.onBeforeRender();
    }

    @Override
    protected void convertInput() {
        String srs = srsTextField.getInput();
        CoordinateReferenceSystem crs = null;
        if (srs != null && !"".equals(srs)) {
            if ("UNKNOWN".equals(srs)) {
                //leave underlying crs unchanged
                if (getModelObject() instanceof CoordinateReferenceSystem) {
                    setConvertedInput(getModelObject());
                }
                return;
            }
            crs = fromSRS(srs);
        }
        setConvertedInput(crs);
    }

    /**
     * Subclasses can override to perform custom behaviors when the SRS is updated, which happens
     * either when the text field is left or when the find dialog returns
     * @param target 
     */
    protected void onSRSUpdated(String srs, AjaxRequestTarget target) {
        // do nothing by default
    }

    /**
     * Sets the panel to be read only.
     */
    public CRSPanel setReadOnly(boolean readOnly) {
        if (readOnly)
            srsTextField.add(READ_ONLY);
        else
            srsTextField.remove(READ_ONLY);
        findLink.setVisible(!readOnly);
        return this;
    }

    /**
     * Returns the underlying CRS for the panel.
     * <p>
     * This method is convenience for:
     * <pre>
     * (CoordinateReferenceSystem) this.getModelObject();
     * </pre>
     * </p>
     */
    public CoordinateReferenceSystem getCRS() {
        convertInput();
        return (CoordinateReferenceSystem) getConvertedInput();
    }

    /*
     * Goes from CRS to SRS. 
     */
    String toSRS(CoordinateReferenceSystem crs) {
        try {
            if (crs != null) {
                Integer epsgCode = CRS.lookupEpsgCode(crs, false);
                return epsgCode != null ? "EPSG:" + epsgCode : "UNKNOWN";
            } else {
                return "UNKNOWN";
            }
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "Could not succesffully lookup an EPSG code", e);
            return null;
        }
    }

    /*
     * Goes from SRS to CRS.
     */
    protected CoordinateReferenceSystem fromSRS(String srs) {
        try {
            return CRS.decode(srs);
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "Unknown EPSG code " + srs, e);
            return null;
        }
    }

    /*
     * Builds the srs list panel component.
     */
    @SuppressWarnings("serial")
    protected SRSListPanel srsListPanel() {
        SRSListPanel srsList = new SRSListPanel(popupWindow.getContentId()) {

            @Override
            protected void onCodeClicked(AjaxRequestTarget target, String epsgCode) {
                popupWindow.close(target);

                String srs = "EPSG:" + epsgCode;
                srsTextField.setModelObject(srs);
                target.addComponent(srsTextField);

                CoordinateReferenceSystem crs = fromSRS(srs);
                CRSPanel.this.setModelObject(crs);
                wktLabel.setDefaultModelObject(crs.getName().toString());
                wktLink.setEnabled(true);
                target.addComponent(wktLink);

                onSRSUpdated(srs, target);
            }
        };
        srsList.setCompactMode(true);
        return srsList;
    }

    /*
     * Panel for displaying the well known text for a CRS.
     */
    public static class WKTPanel extends Panel {

        public WKTPanel(String id, CoordinateReferenceSystem crs) {
            super(id);

            MultiLineLabel wktLabel = new MultiLineLabel("wkt");

            add(wktLabel);

            if (crs != null) {
                wktLabel.setDefaultModel(new Model(crs.toString()));
            }
        }
    }
}