Java tutorial
/* * Copyright 1997-2019 Unidata Program Center/University Corporation for * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307, * support@unidata.ucar.edu. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package ucar.unidata.idv.control; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.ValueAxis; import org.python.core.*; import org.python.util.*; import ucar.unidata.collab.Sharable; import ucar.unidata.data.DataChoice; import ucar.unidata.data.DataInstance; import ucar.unidata.data.grid.GridDataInstance; import ucar.unidata.data.grid.GridUtil; import ucar.unidata.idv.*; import ucar.unidata.util.*; import ucar.unidata.xml.XmlUtil; import ucar.visad.Util; import ucar.visad.display.*; import visad.*; import visad.georef.*; import visad.python.*; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Vector; import javax.swing.*; /** * Allows for the creation of a display by an end user through the use of Jython * * @author Jeff McWhirter/Don Murray * @version $Revision: 1.39 $ */ public class JythonControl extends GridDisplayControl { /** control id for the parameter */ public static final String PARAMNAME_THIS = "displayControl"; /** probe id for the parameter */ public static final String PARAMNAME_PROBE = "probeData"; /** control descriptor for this control */ private static final ControlDescriptor CD = null; /** Symbol for no probe */ public static final String PROBE_NONE = "none"; /** ID for the point probe */ public static final String PROBE_POINT = "point"; /** ID for the level probe */ public static final String PROBE_LEVEL = "level"; /** ID for the area probe */ public static final String PROBE_AREA = "area"; /** ID for the line probe */ public static final String PROBE_VERTICAL = "vertical"; /** ID for the transect probe */ public static final String PROBE_TRANSECT = "transect"; /** list of probes - does this need to be public? */ public static final String[] PROBES = { PROBE_NONE, PROBE_POINT, PROBE_LEVEL, PROBE_VERTICAL, PROBE_TRANSECT, PROBE_AREA }; /** list of probe names - does this need to be public? */ public static final String[] PROBE_NAMES = { "No probe", "Point probe", "Z level probe", "Vertical probe", "Transect probe", "Area probe" }; /** * This control keeps around its own interpreter. */ private PythonInterpreter interpreter; /** Holds the data */ List dataList = new ArrayList(); /** Hashtable of Jython variable */ private Hashtable jythonVars = new Hashtable(); /** Panel for the container */ private JPanel jythonContainer; /** for putting stuff in the legend */ private JPanel sideLegendHolder; /** * For persistence - this is the position of the probe */ private Object initPosition; /** the AreaProbe */ private AreaProbe areaProbe; /** the PointProbe */ private PointProbe pointProbe; /** the LineProbe */ private LineProbe verticalProbe; /** the transect probe */ protected CrossSectionSelector transectProbe; /** the level probe */ private ZSelector levelProbe; /** the last data from a probe */ private Object lastProbeLocation; /** label for showing the probe location */ private JLabel locationLabel; /** The categories */ private String dataCategories; /** The display category */ private String jythonDisplayCategory = ""; /** * The developerMode property. */ private boolean developerMode = false; /** * The probeType property. */ private String probeType = PROBE_POINT; /** text field for the label */ JTextField labelFld; /** text field for the categories */ JTextArea categoriesFld; /** gui */ JTextField displayCategoryFld; /** Any code the user has entered */ private String jythonCode = null; /** * The myname property. */ private String myName; /** The code editor */ private JPythonEditor jythonEditor; /** Holds menu items from jython */ private List saveMenuItems = new ArrayList(); /** Holds menu items from jython */ private List fileMenuItems = new ArrayList(); /** Holds menu items from jython */ private List editMenuItems = new ArrayList(); /** Holds menu items from jython */ private List viewMenuItems = new ArrayList(); /** A flag used when the user selects new data choices. Do we add or replace */ private boolean replaceNewData = false; /** What should we do when the user has chosen new data choices */ private String newDataCallBack = null; /* property for input jythoncode */ private String jythonCodeURL = null; /** * Ctor */ public JythonControl() { } /** * Called to make this kind of Display Control; also calls code to * made the Displayable. * This method is called from inside DisplayControlImpl init(several args). * * @param dataChoice the DataChoice of the moment. * * @return true if successful * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ public boolean init(DataChoice dataChoice) throws VisADException, RemoteException { doMakeProbe(); if (developerMode && (dataCategories == null) && (dataChoice != null)) { List l = dataChoice.getDataCategories(true); if (l != null) { dataCategories = StringUtil.join("\n", l); } } if (jythonCode == null && jythonCodeURL != null) { jythonCode = IOUtil.readContents(jythonCodeURL, ""); } //System.out.println(jythonCode); setContents(doMakeContents()); return true; } /** * init done. call some jython */ public void initDone() { super.initDone(); execJython("handleInit"); try { setTimesForAnimation(); //loadProfile(getPosition()); probeMoved(); } catch (Exception exc) { logException("initDone", exc); } } /** * init set animation time */ private void setTimesForAnimation() throws VisADException, RemoteException { Set myTimes = calculateTimeSet(); if (myTimes == null) { return; } getAnimationWidget().setBaseTimes(myTimes); } /** * init cal animation time */ private Set calculateTimeSet() { List choices = getDataChoices(); if (choices.isEmpty()) { return null; } Set newSet = null; for (int i = 0; i < choices.size(); i++) { try { //VerticalProfileInfo info = getVPInfo(i); GridDataInstance dataInstance = (GridDataInstance) getDataInstance(); Set set = GridUtil.getTimeSet(dataInstance.getGrid()); //System.out.println("di.timeset["+i+"] = " + set); if (set != null) { if (newSet == null) { newSet = set; } else { newSet = newSet.merge1DSets(set); } } } catch (Exception e) { e.printStackTrace(); } } //System.out.println("merged time set = " + newSet); return newSet; } /** * A hook to allow derived classes to tell us to add this * as an animation listener * * @return Add as animation listener */ protected boolean shouldAddAnimationListener() { return true; } /** * Respond to a timeChange event * * @param time new time */ protected void timeChanged(Real time) { try { lastProbeLocation = getProbeLocation(); execJython("handleTime", lastProbeLocation); } catch (Exception exc) { logException("Handling animation time", exc); } super.timeChanged(time); } /** * Make the probe for this instance * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ private void doMakeProbe() throws VisADException, RemoteException { if (getDisplayInfos().size() > 0) { removeDisplayables(); } transectProbe = null; verticalProbe = null; pointProbe = null; areaProbe = null; levelProbe = null; lastProbeLocation = null; boolean displayIs3D = isDisplay3D(); //Make sure we have a probeType if (probeType == null) { probeType = PROBE_NONE; } probeType = probeType.trim(); PropertyChangeListener listener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (!getHaveInitialized()) { return; } if (evt.getPropertyName().equals(SelectorDisplayable.PROPERTY_POSITION)) { probeMoved(); } } }; SelectorDisplayable probe = null; //TODO: Have the non-point probes be fixed in z if (probeType.equals(PROBE_POINT)) { pointProbe = new PointProbe(0.0, 0.0, 0.0); probe = pointProbe; if (initPosition != null) { pointProbe.setPosition((RealTuple) initPosition); } } else if (probeType.equals(PROBE_LEVEL)) { levelProbe = new ZSelector(-1, -1, -1); probe = levelProbe; if (initPosition != null) { levelProbe.setZValue(((Real) initPosition).getValue()); } } else if (probeType.equals(PROBE_AREA)) { areaProbe = new AreaProbe(); probe = areaProbe; if (initPosition != null) { areaProbe.setPosition((RealTuple) initPosition); } } else if (probeType.equals(PROBE_TRANSECT)) { transectProbe = new CrossSectionSelector(); transectProbe.setZValue(.95f); probe = transectProbe; if (initPosition != null) { transectProbe.setPosition((RealTuple[]) initPosition); } } else if (probeType.equals(PROBE_VERTICAL)) { verticalProbe = (getDisplayAltitudeType().equals(Display.Radius)) ? new LineProbe(new RealTuple(RealTupleType.SpatialEarth2DTuple, new double[] { 0, 0 })) : new LineProbe(); if (initPosition != null) { verticalProbe.setPosition((RealTuple) initPosition); } // it is a little colored cube 8 pixels across probe = verticalProbe; } else if (probeType.equals(PROBE_NONE)) { } if (probe != null) { addDisplayable(probe, FLAG_COLOR); Color color = getColor(); if (color == null) { color = Color.blue; } probe.setColor(color); probe.addPropertyChangeListener(listener); probe.setPointSize(getDisplayScale()); probe.setVisible(true); probe.setAutoSize(true); } initPosition = null; } /** * Get a variable. * * @param varName variable name * @return variable corresponding to the name */ public Object getVar(Object varName) { return jythonVars.get(varName); } /** * Set a variable. * * @param varName variable name * @param value variable value */ public void setVar(Object varName, Object value) { if (varName.equals("chart") && jythonVars.get(varName) == null) { jythonVars.put(varName, value); } else if (!varName.equals("chart") && !value.toString().contains("FlatField missing\n")) { jythonVars.put(varName, value); } } public void fixRange() { JFreeChart chart = (JFreeChart) jythonVars.get("chart"); Range x = (Range) jythonVars.get("XRange"); Range y = (Range) jythonVars.get("YRange"); ValueAxis xa = chart.getXYPlot().getDomainAxis(); ValueAxis ya = chart.getXYPlot().getRangeAxis(); //xa.setRange(x); chart.getXYPlot().setRangeAxis(ya); chart.getXYPlot().setDomainAxis(xa); } /** * Make a Jython procedure with one variable. * * @param procName name of the procedure * @param p1 procedure param * @return filled out procedure. */ private String makeProc(String procName, String p1) { return procName + "(" + p1 + ")"; } /** * Make a Jython procedure with two variables. * * @param procName name of the procedure * @param p1 first procedure param * @param p2 second procedure param * * @return filled out procedure. */ private String makeProc(String procName, String p1, String p2) { return procName + "(" + p1 + "," + p2 + ")"; } /** * Set up a property string (ex:, name=value) * * @param name name of the property * @param value value for the property * @return property string */ private String prop(String name, String value) { return name + "=" + value + ";"; } /** * Generate the control's XML */ public void writeToPlugin() { setMyName(labelFld.getText().trim()); String label = getMyName(); if ((label == null) || (label.trim().length() == 0)) { LogUtil.userMessage("You must enter a display name."); return; } /* String filename = FileManager.getWriteFile(FileManager.FILTER_XML, FileManager.SUFFIX_XML); if (filename == null) { return; }*/ label = label.trim(); String id = "jythoncontrol_" + StringUtil.removeWhitespace(label.toLowerCase()); String props = prop("displayName", label) + prop("windowVisible", "true") + prop("probeType", probeType) + prop("developerMode", "false"); String categories = StringUtil.join(";", StringUtil.split(categoriesFld.getText(), "\n", true, true)); String attrs = "\n\t" + XmlUtil.attr(CD.ATTR_ID, id) + "\n" + "\t" + XmlUtil.attr(CD.ATTR_DESCRIPTION, label) + "\n" + "\t" + XmlUtil.attr(CD.ATTR_CLASS, getClass().getName()) + "\n" + "\t" + XmlUtil.attr(CD.ATTR_LABEL, getMyName()) + "\n" + XmlUtil.attr(CD.ATTR_DISPLAYCATEGORY, displayCategoryFld.getText().trim()) + "\n" + "\t" + XmlUtil.attr(CD.ATTR_CATEGORIES, categories) + "\n" + "\t" + XmlUtil.attr(CD.ATTR_CANSTANDALONE, "false") + "\n" + "\t" + XmlUtil.attr(CD.ATTR_PROPERTIES, props) + "\n"; String body = "<property name=\"jythonCode\"><![CDATA[" + jythonCode + "]]></property>"; String xml = XmlUtil.tag(CD.TAG_CONTROL, attrs, body); // try { getControlContext().getIdv().getPluginManager().addText(xml, "controls.xml"); // IOUtil.writeFile(filename, xml); // } catch (Exception exc) { // logException("Error writing file:" + filename, exc); // } } /** * We have new data. Reload * * @throws RemoteException On badness * @throws VisADException On badness */ protected void resetData() throws VisADException, RemoteException { dataList = null; execJython("handleData"); lastProbeLocation = getProbeLocation(); execJython("handleTime", lastProbeLocation); } /** * Get the list of DataChoices * @return list of DataChoices * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ public List getDataList() throws RemoteException, VisADException { if ((dataList == null) || (dataList.size() == 0)) { dataList = new ArrayList(); List choices = getInitDataChoices(); for (int i = 0; i < choices.size(); i++) { Data data = ((DataChoice) choices.get(i)).getData(getDataSelection()); dataList.add(data); } } return dataList; } /** * Execute the jython method * * @param method jython method to call */ public void execJython(String method) { execJython(method, null); } /** * Exectue the probe data * * * @param method method * @param probeLocation probe location */ private void execJython(String method, Object probeLocation) { if ((method == null) || (method.length() == 0)) { return; } if (method.equals("handleInit")) { saveMenuItems = new ArrayList(); fileMenuItems = new ArrayList(); editMenuItems = new ArrayList(); viewMenuItems = new ArrayList(); } String code = ""; try { PythonInterpreter interp = getMyInterpreter(); if (probeLocation != null) { code = makeProc(method, PARAMNAME_THIS, PARAMNAME_PROBE); interp.set(PARAMNAME_PROBE, probeLocation); } else { code = makeProc(method, PARAMNAME_THIS); } interp.set(PARAMNAME_THIS, this); interp.exec(code); } catch (Exception exc) { logException("Error evaluating:" + code, exc); } } /** * Sample the first data at the probe position * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public Data sample() throws RemoteException, VisADException { return sampleIndex(0, false); } /** * Sample the first data at the probe position and at the current animation time * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public Data sampleAtTime() throws RemoteException, VisADException { return sampleIndex(0, true); } /** * Sample the data at the index at the probe position * * @param index Index in the data list * @param atTime If true then also sample at the current animation time * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public Data sampleIndex(int index, boolean atTime) throws RemoteException, VisADException { EarthLocationTuple[] probeData = getProbeLocation(); if (probeData == null) { return null; } List data = getDataList(); if ((data == null) || (index >= data.size())) { return null; } return sampleData(probeData, (FieldImpl) data.get(index), atTime); } /** * Sample all the data at the probe point * * @return Sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public List sampleAll() throws RemoteException, VisADException { return sampleAll(false); } /** * Sample all the data at the probe point at the current animation time * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public List sampleAllAtTime() throws RemoteException, VisADException { return sampleAll(true); } /** * Samle all the data * * @param atTime If true then also sample at the animation time * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ private List sampleAll(boolean atTime) throws RemoteException, VisADException { EarthLocationTuple[] probeData = getProbeLocation(); if (probeData == null) { return null; } List data = getDataList(); if ((data == null) || (data.size() == 0)) { return null; } List result = new ArrayList(); for (int i = 0; i < data.size(); i++) { result.add(sampleData(probeData, (FieldImpl) data.get(i), atTime)); } return result; } /** * Sample the field at the probe location * * @param field field to sample * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public Data sampleDataAtProbe(FieldImpl field) throws RemoteException, VisADException { return sampleData(getProbeLocation(), field); } /** * Sample at location * * @param loc location * @param field field to sample * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public Data sampleData(EarthLocationTuple[] loc, FieldImpl field) throws RemoteException, VisADException { return sampleData(loc, field, false); } /** * Get current animation time or null of none * * @return animation time * * @throws RemoteException On badness * @throws VisADException On badness */ public Real getAnimationTime() throws RemoteException, VisADException { Animation animation = getViewAnimation(); if (animation != null && animation.getAniValue() != null) { return animation.getAniValue(); } else { animation = getInternalAnimation(null); if (animation != null) { return animation.getAniValue(); } } return null; } /** * Get all animation times or null if none * * @return animation time * * @throws RemoteException On badness * @throws VisADException On badness */ public List getAnimationTimes() throws RemoteException, VisADException { Animation animation = getViewAnimation(); if (animation != null) { Set set = animation.getSet(); return Util.toList(set); } return null; } /** * Get times from data * * @return animation time * * @throws RemoteException On badness * @throws VisADException On badness */ public List getTimesFromData() throws RemoteException, VisADException { List data = getDataList(); List times = new ArrayList(); for (int dataIdx = 0; dataIdx < data.size(); dataIdx++) { FieldImpl field = (FieldImpl) data.get(dataIdx); Set timeSet = GridUtil.getTimeSet(field); if (timeSet != null) { List dataTimes = Util.toList(timeSet); for (int timeIdx = 0; timeIdx < dataTimes.size(); timeIdx++) { Object t = dataTimes.get(timeIdx); if (!times.contains(t)) { times.add(t); } } } } return times; } /** * Sample the field at the location and maybe at the animation time * * @param loc location * @param field field * @param atTime if true then also sample at anim time * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ public Data sampleData(EarthLocationTuple[] loc, FieldImpl field, boolean atTime) throws RemoteException, VisADException { Field sample = doSample(loc, field); if (sample == null) { return null; } if (atTime) { Real aniValue = getAnimationTime(); if ((aniValue != null) && !aniValue.isMissing()) { Set timeSet = sample.getDomainSet(); Unit setUnit = timeSet.getSetUnits()[0]; if (Unit.canConvert(aniValue.getUnit(), setUnit)) { double timeValue = aniValue.getValue(timeSet.getSetUnits()[0]); int[] index = timeSet.doubleToIndex(new double[][] { { timeValue } }); return sample.getSample(index[0]); } } } return sample; } /** * sample * * @param loc location to sample * @param field field to sample * * @return sampled data * * @throws RemoteException On badness * @throws VisADException On badness */ private Field doSample(EarthLocationTuple[] loc, FieldImpl field) throws RemoteException, VisADException { if ((loc == null) || (field == null)) { return null; } int samplingMode = getDefaultSamplingModeValue(); if (probeType.equals(PROBE_POINT)) { if (GridUtil.is3D(field)) { return GridUtil.sample(field, loc[0], samplingMode); } else { return GridUtil.sample(field, loc[0].getLatLonPoint(), samplingMode); } } else if (probeType.equals(PROBE_LEVEL)) { return GridUtil.sliceAtLevel(field, loc[0].getAltitude(), samplingMode); } else if (probeType.equals(PROBE_AREA)) { throw new IllegalArgumentException("Sampling on area probe is not supported"); } else if (probeType.equals(PROBE_TRANSECT)) { return GridUtil.sliceAlongLatLonLine(field, loc[0].getLatLonPoint(), loc[1].getLatLonPoint(), samplingMode); } else if (probeType.equals(PROBE_VERTICAL)) { return GridUtil.getProfileAtLatLonPoint(field, loc[0].getLatLonPoint(), samplingMode); } return null; } /** * Return the appropriate label text for the menu. * @return the label text */ protected String getChangeParameterLabel() { return "Add Parameter..."; } /** * Gets called whne user has chosen new data * * @param newChoices new data choices * * @throws RemoteException On badness * @throws VisADException On badness */ protected void addNewData(List newChoices) throws VisADException, RemoteException { dataList = null; if (replaceNewData) { setDataChoices(newChoices); } else { appendDataChoices(newChoices); } if (newDataCallBack == null) { execJython("handleData"); } else { execJython(newDataCallBack); } } /** * Hook to allow jython to call to bring up data choice selector * * @param message message to use in dialog */ public void selectData(String message) { addData(message); } /** * Hook to allow jython to call to bring up data choice selector * * @param message message to use in dialog */ public void addData(String message) { selectData(message, null, false, false, null); } /** * Hook to allow jython to call to bring up data choice selector * * @param message message to use in dialog * @param callback The jython procedure to callback */ public void addData(String message, String callback) { selectData(message, callback, false, false, null); } /** * Hook to allow jython to call to bring up data choice selector * * @param message message to use in dialog */ public void replaceData(String message) { selectData(message, null, true, false, null); } /** * Hook to allow jython to call to bring up data choice selector * * @param message message to use in dialog * @param callback The jython procedure to callback */ public void replaceData(String message, String callback) { selectData(message, callback, true, false, null); } /** * Hook to allow jython to call to bring up data choice selector * * @param message message to use in dialog * @param callback The jython procedure to callback * @param replace If true then we remove the current list of data choices and replace it with the selected ones. * @param multiples Select multiples * @param categories Possibly null list of data categories to use */ public void selectData(String message, String callback, boolean replace, boolean multiples, List categories) { replaceNewData = replace; newDataCallBack = callback; if (categories != null) { popupDataDialog(message, null, multiples, categories); } else { popupDataDialog(message, null, multiples, getCategories()); } newDataCallBack = null; replaceNewData = false; } /** * Remove this control. * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ public void doRemove() throws RemoteException, VisADException { super.doRemove(); if (interpreter != null) { getControlContext().getJythonManager().removeInterpreter(interpreter); interpreter = null; } } /** * Get the interpreter for this control. * @return this control's interpreter * * @throws Exception On badness */ private PythonInterpreter getMyInterpreter() throws Exception { if (interpreter == null) { interpreter = getControlContext().getJythonManager().createInterpreter(); } String code = getJythonCode(); if (code != null) { interpreter.exec(code); } return interpreter; } /** * Get the probe being used. * @return current probe. */ public Displayable getCurrentProbe() { if (pointProbe != null) { return pointProbe; } if (levelProbe != null) { return levelProbe; } if (verticalProbe != null) { return verticalProbe; } if (transectProbe != null) { return transectProbe; } if (areaProbe != null) { return areaProbe; } return null; } /** * Get the probe's position * @return position of the probe * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ public Object getProbePosition() throws VisADException, RemoteException { if (pointProbe != null) { return pointProbe.getPosition(); } if (levelProbe != null) { return levelProbe.getPosition(); } if (verticalProbe != null) { return verticalProbe.getPosition(); } if (transectProbe != null) { return transectProbe.getPosition(); } if (areaProbe != null) { return areaProbe.getArea(); } return null; } /** * Set the probe position property. * * @param p position for probe. */ public void setProbePosition(Object p) { initPosition = p; } /** * Called when the probe is moved. * */ private void probeMoved() { try { EarthLocationTuple[] probeLocation = getProbeLocation(); if (probeLocation != null) { if (Misc.equals(lastProbeLocation, probeLocation)) { return; } lastProbeLocation = probeLocation; execJython("handleProbe", probeLocation); } } catch (Exception exc) { logException("Moving probe", exc); } } /** * Return the current probe position in X/Y space. * * @return a 2-D array of the form data[N][0] = X, data[N][1] = Y, * data[N][2] = Z * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ public double[][] getProbeXYZ() throws VisADException, RemoteException { Displayable currentProbe = getCurrentProbe(); if (currentProbe == null) { return null; } if (pointProbe != null) { return getPointProbeLocation(); } if (areaProbe != null) { return getAreaProbeLocation(); } if (verticalProbe != null) { return getVerticalProbeLocation(); } if (transectProbe != null) { return getTransectProbeLocation(); } if (levelProbe != null) { return getLevelProbeLocation(); } return null; } /** * Return an array that holds the location of the current probe. * For point, level and vertical probes the length is 1 * For the horizonal probe the length 2 (the end points of the probe line) * For the area probe the length is 4 (upper-left, upper-right, * lower-right, lower-left) * * @return An array holding the probe location * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ public EarthLocationTuple[] getProbeLocation() throws VisADException, RemoteException { Displayable currentProbe = getCurrentProbe(); if (currentProbe == null) { return null; } double[][] data = getProbeXYZ(); if (data == null) { return null; } EarthLocationTuple[] elt = new EarthLocationTuple[data.length]; for (int i = 0; i < data.length; i++) { elt[i] = getELT(data[i][0], data[i][1], data[i][2]); } return elt; } /** * A utility method to create a double array of length 3 * * @param x x value * @param y y value * * @return a double array holding {x, y, 0.0} */ private double[] getArray(double x, double y) { return getArray(x, y, 0.0); } /** * A utility method to create a double array of length 3 * * * @param x x value * @param y y value * @param z z value * * @return a double array holding {x, y, z} */ private double[] getArray(double x, double y, double z) { return new double[] { x, y, z }; } /** * A utility method to create a EarthLocationTuple * * @param x x coordinate * @param y y coordinate * @param z z coordinate * * @return an EarthLocationTuple from the given x/y/z coordinates * * @throws RemoteException On badness * @throws VisADException On badness */ private EarthLocationTuple getELT(double x, double y, double z) throws VisADException, RemoteException { return (EarthLocationTuple) boxToEarth(new double[] { x, y, z }); } /** * Get the location of the point probe. * * @return The location (lat,lon,alt) of the point probe * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ private double[][] getPointProbeLocation() throws VisADException, RemoteException { double[] values = pointProbe.getPosition().getValues(); return new double[][] { getArray(values[0], values[1], values[2]) }; } /** * Get the location of the area probe. * * @return Array of size 2 of LatLonPoints that are the upper left * and lower right points of the area. * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ private double[][] getAreaProbeLocation() throws VisADException, RemoteException { double[] values = areaProbe.getArea().getValues(); double left = Math.min(values[0], values[2]); double right = Math.max(values[0], values[2]); double top = Math.max(values[1], values[3]); double bottom = Math.min(values[1], values[3]); return new double[][] { getArray(left, top), getArray(right, top), getArray(right, bottom), getArray(left, bottom) }; } /** * Get the location of the vertical probe. * * @return The Lat/Lon position of the vertical probe * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ private double[][] getVerticalProbeLocation() throws VisADException, RemoteException { double[] data; RealTuple position = verticalProbe.getPosition(); RealTupleType rttype = (RealTupleType) position.getType(); if (rttype.equals(RealTupleType.SpatialCartesian2DTuple)) { // get earth location of the x,y position in the VisAD display double[] values = position.getValues(); data = getArray(values[0], values[1]); } else if (rttype.equals(RealTupleType.SpatialEarth2DTuple)) { Real[] reals = position.getRealComponents(); data = getArray(reals[1].getValue(), reals[0].getValue()); } else if (rttype.equals(RealTupleType.LatitudeLongitudeTuple)) { Real[] reals = position.getRealComponents(); data = getArray(reals[0].getValue(), reals[1].getValue()); } else { throw new VisADException("Can't convert position to navigable point"); } if (data != null) { return new double[][] { data }; } return null; } /** * Get the location of the Transect probe. * * @return An array of length 2 that holds the start point and * end point (as lat/lon) * of the probe. * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ private double[][] getTransectProbeLocation() throws VisADException, RemoteException { RealTuple start = transectProbe.getStartPoint(); RealTuple end = transectProbe.getEndPoint(); double[] v1 = start.getValues(); double[] v2 = end.getValues(); return new double[][] { getArray(v1[0], v1[1]), getArray(v2[0], v2[1]) }; } /** * Get the location of the level probe. * * @return The altitude of the level probe. * * @throws RemoteException Java RMI error * @throws VisADException VisAD Error */ private double[][] getLevelProbeLocation() throws VisADException, RemoteException { return new double[][] { getArray(0.0, 0.0, levelProbe.getPosition().getValue()) }; } /** * Method called by other classes that share the probe. * * @param from other class. * @param dataId type of sharing * @param data Array of data being shared. In this case, the first * (and only?) object in the array is the level */ public void receiveShareData(Sharable from, Object dataId, Object[] data) { /* * if (dataId.equals (SHARE_LEVEL)) { * try { * loadDataAtLevel ((Real)data[0]); * } catch (Exception exc) { * LogUtil.printException (log_, "receiveShareData.level", exc); * } * return; * } */ super.receiveShareData(from, dataId, data); } /** * Get the probe name. * * @param probe probe name to find. * @return probe name */ private String getProbeName(String probe) { for (int i = 0; i < PROBES.length; i++) { if (PROBES[i].equals(probe)) { return PROBE_NAMES[i]; } } return "No probe"; } /** * Make some Plan view controls for the UI. * @return create the contents for the UI. */ public Container doMakeContents() { jythonContainer = new JPanel(new BorderLayout()); if (developerMode) { return doMakeDeveloperContents(); } else { return jythonContainer; } } /** * Make the developer UI contents * @return UI for developer code */ private JComponent doMakeDeveloperContents() { labelFld = new JTextField((myName != null) ? myName : "", 15); labelFld.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { setMyName(labelFld.getText().trim()); } }); Vector probeItems = new Vector(); for (int i = 0; i < PROBES.length; i++) { probeItems.add(new TwoFacedObject(PROBE_NAMES[i], PROBES[i])); } final JComboBox probeCbx = new JComboBox(probeItems); probeCbx.setSelectedItem(new TwoFacedObject(getProbeName(probeType), probeType)); probeCbx.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { try { probeType = ((TwoFacedObject) probeCbx.getSelectedItem()).getId().toString(); doMakeProbe(); } catch (Exception exc) { logException("Changing probe type", exc); } } }); displayCategoryFld = new JTextField(jythonDisplayCategory, 15); categoriesFld = new JTextArea("", 4, 20); if (dataCategories != null) { categoriesFld.setText(dataCategories); } Component[] comps = { GuiUtils.rLabel("Display name: "), GuiUtils.left(labelFld), GuiUtils.rLabel("Display Category:"), GuiUtils.left(displayCategoryFld), GuiUtils.top(GuiUtils.rLabel("Data Categories:")), GuiUtils.left(new JScrollPane(categoriesFld)), GuiUtils.rLabel("Probe Type:"), GuiUtils.left(GuiUtils.hflow(Misc.newList(probeCbx, GuiUtils.rLabel(" Probe Color: "), doMakeColorControl(getColor())))) }; GuiUtils.tmpInsets = GuiUtils.INSETS_5; JPanel fldPanel = GuiUtils.doLayout(comps, 2, GuiUtils.WT_NYN, GuiUtils.WT_N); try { if (jythonCode == null) { jythonCode = IOUtil.readContents("/ucar/unidata/idv/control/jythoncontrol.py", ""); } jythonEditor = new JPythonEditor(); jythonEditor.setText(jythonCode); jythonEditor.setPreferredSize(new Dimension(400, 300)); } catch (VisADException exc) { logException("Creating Jython editor", exc); } JComponent jythonPanel = new JScrollPane(jythonEditor); JTabbedPane tab = GuiUtils.getNestedTabbedPane(); tab.add("Settings", GuiUtils.top(fldPanel)); List buttons = Misc.newList(GuiUtils.makeButton("Evaluate Init", this, "execJython", "handleInit"), GuiUtils.makeButton("Evaluate Data", this, "execJython", "handleData")); JPanel buttonPanel = GuiUtils.left(GuiUtils.hbox(buttons)); tab.add("Jython", GuiUtils.topCenter(buttonPanel, jythonPanel)); tab.add("Result GUI", jythonContainer); return tab; } /** * Return the extra legend component * * @param legendType side or bottom * * @return component to put in legend */ protected JComponent getExtraLegendComponent(int legendType) { JComponent parentComp = super.getExtraLegendComponent(legendType); if (legendType == BOTTOM_LEGEND) { return parentComp; } if (sideLegendHolder == null) { sideLegendHolder = new JPanel(new BorderLayout()); } return sideLegendHolder; } /** * Add a python component * * @param comp component to add */ public void addJythonComponent(Component comp) { setJythonComponent(comp); } /** * Hook to call from jython to add in the legend component * * @param comp legend component */ public void setLegendComponent(Component comp) { if (sideLegendHolder == null) { sideLegendHolder = new JPanel(new BorderLayout()); } sideLegendHolder.removeAll(); if (comp != null) { sideLegendHolder.add(BorderLayout.CENTER, comp); } } /** * Hook to call from jython to define gui * * @param comp gui */ public void setJythonComponent(Component comp) { jythonContainer.removeAll(); if (comp != null) { jythonContainer.add(BorderLayout.CENTER, comp); } redoGuiLayout(); } /** * Add the relevant file menu items into the list * * @param items List of menu items * @param forMenuBar Is this for the menu in the window's menu bar or * for a popup menu in the legend */ protected void getSaveMenuItems(List items, boolean forMenuBar) { if (developerMode) { items.add(GuiUtils.makeMenuItem("Write to Plugin", this, "writeToPlugin")); } items.addAll(saveMenuItems); super.getSaveMenuItems(items, forMenuBar); } /** * add to menu * * @param items list of menu items to add to * @param forMenuBar for menu bar */ protected void getFileMenuItems(List items, boolean forMenuBar) { items.addAll(fileMenuItems); super.getFileMenuItems(items, forMenuBar); } /** * add to menu * * @param items list of menu items to add to * @param forMenuBar for menu bar */ protected void getEditMenuItems(List items, boolean forMenuBar) { items.addAll(editMenuItems); super.getEditMenuItems(items, forMenuBar); } /** * add to menu * * @param items list of menu items to add to * @param forMenuBar for menu bar */ protected void getViewMenuItems(List items, boolean forMenuBar) { items.addAll(viewMenuItems); super.getViewMenuItems(items, forMenuBar); } /** * add the menu item to the list * * @param l list of items * @param name menu item name * @param method jython method to call */ private void addMenuItem(List l, String name, String method) { l.add(GuiUtils.makeMenuItem(name, this, "execJython", method)); } /** * Hook to call from jython to add to menu * * @param name menu item name * @param method jython method name to call */ public void addFileMenuItem(String name, String method) { addMenuItem(fileMenuItems, name, method); } /** * Hook to call from jython to add to menu * * @param name menu item name * @param method jython method name to call */ public void addSaveMenuItem(String name, String method) { addMenuItem(saveMenuItems, name, method); } /** * Hook to call from jython to add to menu * * @param name menu item name * @param method jython method name to call */ public void addViewMenuItem(String name, String method) { addMenuItem(viewMenuItems, name, method); } /** * Hook to call from jython to add to menu * * @param name menu item name * @param method jython method name to call */ public void addEditMenuItem(String name, String method) { addMenuItem(editMenuItems, name, method); } /** * Set the ProbeType property. * * @param value The new value for ProbeType */ public void setProbeType(String value) { probeType = value; } /** * Get the ProbeType property. * * @return The ProbeType */ public String getProbeType() { return probeType; } /** * Set the DeveloperMode property. * * @param value The new value for DeveloperMode */ public void setDeveloperMode(boolean value) { developerMode = value; } /** * Get the DeveloperMode property. * * @return The DeveloperMode */ public boolean getDeveloperMode() { return developerMode; } /** * Set the MyName property. * * @param value The new value for MyName */ public void setMyName(String value) { myName = value; } /** * Get the MyName property. * * @return The MyName */ public String getMyName() { if (labelFld != null) { return labelFld.getText().trim(); } return myName; } /** * Set the CategoryString property. * * @param value The new value for CategoryString */ public void setDataCategories(String value) { dataCategories = value; } /** * Get the CategoryString property. * * @return The CategoryString */ public String getDataCategories() { if (categoriesFld != null) { return categoriesFld.getText(); } return dataCategories; } /** * Set the DisplayCategory property. * * @param value The new value for DisplayCategory */ public void setJythonDisplayCategory(String value) { jythonDisplayCategory = value; } /** * Get the DisplayCategory property. * * @return The DisplayCategory */ public String getJythonDisplayCategory() { if (displayCategoryFld != null) { return displayCategoryFld.getText(); } return jythonDisplayCategory; } /** * Set the JythonCode property. * * @param value The new value for JythonCode */ public void setJythonCode(String value) { jythonCode = value; } /** * Get the JythonCode property. * * @return The JythonCode */ public String getJythonCode() { if (developerMode) { if (jythonEditor != null) { return jythonEditor.getText(); } return null; } return jythonCode; } /** * Set the JythonCode property. * * @param value The new value for JythonCode */ public void setJythonCodeURL(String value) { jythonCodeURL = value; } /** * Get the JythonCode property. * * @return The JythonCode */ public String getJythonCodeURL() { return jythonCodeURL; } }