/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program 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 program 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
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: Plot.java,v 1.64 2009/01/08 15:21:52 ogor Exp $
*
* Changes
* -------
* 25-Sep-2003 : Initial public release (NB);
*
*/
package jsynoptic.builtin;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.io.Serializable;
import java.text.ChoiceFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.ResourceBundle;
import java.util.Vector;
import javax.swing.JDialog;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.CompoundEdit;
import jsynoptic.base.ContextualActionProvider;
import jsynoptic.base.DataSourceConsumer;
import jsynoptic.base.Linkable;
import jsynoptic.base.SelectionContextualActionProvider;
import jsynoptic.builtin.ui.CurvePropertiesPanel;
import jsynoptic.builtin.ui.LimitPropertiesPanel;
import jsynoptic.builtin.ui.PlotPropertiesDialogBox;
import jsynoptic.builtin.ui.PlotPropertiesPanel;
import jsynoptic.builtin.ui.CurvePropertiesPanel.CurveParameters;
import jsynoptic.ui.JSynoptic;
import jsynoptic.ui.LongAction;
import simtools.data.DataException;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceCollection;
import simtools.data.DataSourcePool;
import simtools.data.UnsupportedOperation;
import simtools.diagram.DiagramSelection;
import simtools.diagram.DiagramComponent.ContextualDrawing;
import simtools.diagram.DiagramComponent.ContextualDrawingProvider;
import simtools.shapes.AbstractShape;
import simtools.shapes.AxisLabelFormatter;
import simtools.shapes.AxisShape;
import simtools.shapes.CurveShape;
import simtools.shapes.LimitShape;
import simtools.shapes.PlotShape;
import simtools.shapes.StrokeParameters;
import simtools.shapes.AxisShape.AxePropertiesNames;
import simtools.shapes.CurveShape.CurvePoint;
import simtools.shapes.CurveShape.CurveShapePropertiesNames;
import simtools.shapes.LimitShape.LimitShapePropertiesNames;
import simtools.shapes.undo.PropertyChangeEdit;
import simtools.ui.CustomizedLocale;
import simtools.ui.JPropertiesPanel;
import simtools.ui.MenuResourceBundle;
import simtools.ui.PlotInformationDialog;
/**
* A Plot shape to display curves using up to 2 pairs of axes
* X and Y primary and secondary axes are independent
*
* @author Nicolas Brodu
* @author Claude CAZENAVE
*/
public class Plot extends PlotShape
implements
ContextualActionProvider,
SelectionContextualActionProvider,
Linkable,
DataSourceConsumer,
ContextualDrawingProvider
{
static final long serialVersionUID = 4941787241403275071L;
/**
* Prefered number of rows
* if the value is < 2 then the user don't want
* to fix a prefered number of rows
*/
static public int preferredXGraduation = 0;
/**
* Prefered number of columns
* if the value is < 0 then the user don't want
* to fix a prefered number of colmuns
*/
static public int preferredYGraduation = 0;
static public boolean DEFAULT_DISPLAY_DATA_SOURCE_ID = false;
// Linkable shape
protected String link;
// Contextual drawings : zoom and translate drawings
protected transient ContextualDrawing zoomDrawing, translateDrawing;
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getShapeName()
*/
public String getShapeName(){
return Builtin.resources.getString("Plot");
}
/** Resources */
public static MenuResourceBundle resources;
static {
try {
resources = (MenuResourceBundle) ResourceBundle.getBundle(
"jsynoptic.builtin.resources.PlotResources",
CustomizedLocale.get()
);
} catch (Exception e) {
System.err.println("Can't load Plot resources");
System.exit(0);
}
}
protected static Color[] defaultPalette = {
Color.blue,
Color.red,
Color.green,
Color.magenta,
Color.cyan,
Color.orange,
Color.pink,
Color.black,
Color.yellow
};
protected int paletteIndex;
protected transient DataSource primaryX;
protected transient DataSource secondaryX;
protected Vector primaryCurves; // CurveShapes using primary Y axis
protected Vector secondaryCurves; // CurveShapes using secondary Y axis
// Index management
protected boolean isPrimaryBounded;
protected long primaryStartIndex, primaryEndIndex;
protected boolean isSecondaryBounded;
protected long secondaryStartIndex, secondaryEndIndex;
protected transient int nbXGraduation = preferredXGraduation;
protected transient int nbYGraduation = preferredYGraduation;
/**@deprecated Do not use these attributes anymore, use axesRangeArray[PX].min, axesRangeArray[PX].max, axesRangeArray[PX].step instead.*/
protected double pxmin, pxmax, pxstep;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[PX].label instead*/
protected String pxlabel;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[PX].auto instead*/
protected boolean autopx=true;
/**@deprecated Do not use these attributes anymore, use axesRangeArray[PY].min, axesRangeArray[PY].max, axesRangeArray[PY].step instead.*/
protected double pymin, pymax, pystep;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[PY].label instead*/
protected String pylabel;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[PY].auto instead*/
protected boolean autopy=true;
/**@deprecated Do not use these attributes anymore, use axesRangeArray[SX].min, axesRangeArray[SX].max, axesRangeArray[SX].step instead.*/
protected double sxmin, sxmax, sxstep;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[SX].label instead*/
protected String sxlabel;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[SX].auto instead*/
protected boolean autosx=true;
/**@deprecated Do not use these attributes anymore, use axesRangeArray[SY].min, axesRangeArray[SY].max, axesRangeArray[SY].step instead.*/
protected double symin, symax, systep;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[SY].label instead*/
protected String sylabel;
/**@deprecated Do not use this attribute anymore, use axesRangeArray[PX].auto instead*/
protected boolean autosy=true;
/**@deprecated Do not use these attributes anymore, use axesRangeArray[PX].validity, axesRangeArray[PY].validity, axesRangeArray[SX].validity, axesRangeArray[SY].validity instead.*/
protected boolean pxvaluesOK, pyvaluesOK, sxvaluesOK, syvaluesOK;
/**Constant indexes to find PX, PY, SX and SY limits values and validity.*/
protected static final int PX=0, PY=1, SX=2, SY=3;
/** A constant to know the number of axes.*/
protected static final int AXE_NUMBER = 4;
/** axes names for property managment */
protected static final String[] AXIS_ID = {"primX","primY","secX","secY"};
/**The array of AxeRange.*/
protected AxeRange[] axesLimitsArray = new AxeRange[AXE_NUMBER];
public Plot(int ox, int oy, int width, int height) {
super(ox, oy, width, height);
primaryX = null;
secondaryX = null;
primaryCurves = null;
secondaryCurves = null;
//initialiez axes ranges.
axesLimitsArray = new AxeRange[AXE_NUMBER];
for (int i = 0; i < axesLimitsArray.length; i++) {
axesLimitsArray[i] = new AxeRange();
//Axes limits are not valid (because not initialized yet).
axesLimitsArray[i].validity = false;
}
paletteIndex = 0;
}
protected AbstractShape cloneShape() {
Plot p = (Plot)super.cloneShape();
if (primaryCurves!=null){
p.primaryCurves=new Vector();
for(int i=0;i<primaryCurves.size();i++){
int rank=_curves.indexOf(getCurve((CurveShape)primaryCurves.get(i)));
CurveShape cs=(CurveShape)((Curve)p._curves.get(rank)).shape;
p.primaryCurves.add(cs);
}
}
if (secondaryCurves!=null){
p.secondaryCurves=new Vector();
for(int i=0;i<secondaryCurves.size();i++){
int rank=_curves.indexOf(getCurve((CurveShape)secondaryCurves.get(i)));
CurveShape cs=(CurveShape)((Curve)p._curves.get(rank)).shape;
p.secondaryCurves.add(cs);
}
}
p.axesLimitsArray = new AxeRange[AXE_NUMBER];
for (int i = 0; i < p.axesLimitsArray.length; i++) {
p.axesLimitsArray[i] = new AxeRange(axesLimitsArray[i].min,
axesLimitsArray[i].max,
axesLimitsArray[i].step,
axesLimitsArray[i].validity,
axesLimitsArray[i].auto,
axesLimitsArray[i].label,
axesLimitsArray[i].floatingAxe,
axesLimitsArray[i].floatingAxeRange);
}
return p;
}
public boolean setPrimaryX(DataSource ds, boolean background) {
return setX(ds, true, background);
}
public DataSource getPrimaryX() {
return primaryX;
}
public boolean addPrimaryY(DataSource ds, boolean background) {
return addY(ds,true,true, background);
}
public boolean setSecondaryX(DataSource ds, boolean background) {
return setX(ds, false, background);
}
public DataSource getSecondaryX() {
return secondaryX;
}
public boolean addSecondaryY(DataSource ds, boolean background) {
return addY(ds,false,true, background);
}
public boolean addSecondaryYForSecondaryX(DataSource ds, boolean background) {
return addY(ds,false,false, background);
}
public boolean addPrimaryYForSecondaryX(DataSource ds, boolean background) {
return addY(ds,true,false, background);
}
// Our own functions
public void setX(DataSource ds, boolean primary) {
if (ds!=null){
Rectangle bounds = getBounds();
try {
long istart = ds.computeStartIndex();
long iend = ds.computeLastIndex();
if (primary) {
isPrimaryBounded = true;
primaryStartIndex = istart;
primaryEndIndex = iend;
} else {
isSecondaryBounded = true;
secondaryStartIndex = istart;
secondaryEndIndex = iend;
}
}
catch (UnsupportedOperation uo1) {
if (primary) isPrimaryBounded = false;
else isSecondaryBounded = false;
}
DataSource oldX;
String label = DEFAULT_DISPLAY_DATA_SOURCE_ID? DataInfo.getAliasOrIdwithUnit(ds) : DataInfo.getAliasOrLabelwithUnit(ds);
if (primary) {
oldX = primaryX;
primaryX = ds;
axesLimitsArray[PX].label = label;
}
else {
setSecondaryAxis(true, true);
oldX = secondaryX;
secondaryX = ds;
axesLimitsArray[SX].label = label;
}
// update all curves using the old x source
if (primaryCurves!=null) {
for (Iterator it = primaryCurves.iterator(); it.hasNext(); ) {
CurveShape cs = (CurveShape)it.next();
try{
if (cs.getXSource()==oldX) {
cs.setData(ds, cs.getYSource());
if (isPrimaryBounded) cs.setSlice(primaryStartIndex, primaryEndIndex);
}
}catch (DataException e){}
}
}
if (secondaryCurves!=null) {
for (Iterator it = secondaryCurves.iterator(); it.hasNext(); ) {
CurveShape cs = (CurveShape)it.next();
try{
if (cs.getXSource()==oldX) {
cs.setData(ds, cs.getYSource());
if (isSecondaryBounded) cs.setSlice(secondaryStartIndex, secondaryEndIndex);
}
}catch (DataException e){}
}
}
repaintDiagram(bounds);
}
}
// primary/secondary => no code dup
protected boolean setX(DataSource ds, boolean primary, boolean background) {
if (ds==null) return false;
if (background){
new LongAction(LongAction.LONG_ACTION_SHAPE | LongAction.LONG_ACTION_SOURCE,
new Object[]{ds, new Boolean(primary), new Boolean(background)},
new Object[]{ds, this} ){
protected void doAction() {
Object[] obar = (Object[])param;
DataSource ds = (DataSource)obar[0];
boolean primary = ((Boolean)obar[1]).booleanValue();
setX(ds, primary);
}
}.start(background);
}else{
setX(ds, primary);
}
return !background;
}
protected LimitShape doAddLimitAction(boolean isVertical, boolean useSecondary, double position, String name){
Rectangle bounds = getBounds();
LimitShape cs = new LimitShape(isVertical, position);
insertLimit(cs,useSecondary);
setLimitLabel(cs, name);
setLimitColor(cs, defaultPalette[paletteIndex++]);
if (paletteIndex >= defaultPalette.length) paletteIndex = 0;
repaintDiagram(bounds);
return cs;
}
protected CurveShape createCurveShape(DataSource xds, DataSource yds){
return new CurveShape(xds, yds);
}
protected CurveShape doAddYAction(Object[] obar){
DataSource ds = (DataSource)obar[0];
boolean primary = ((Boolean)obar[1]).booleanValue();
boolean usePrimaryX = ((Boolean)obar[2]).booleanValue();
Rectangle bounds = getBounds();
CurveShape cs;
if (usePrimaryX) {
cs = createCurveShape(primaryX, ds);
if (isPrimaryBounded) cs.setSlice(primaryStartIndex, primaryEndIndex);
} else {
cs = createCurveShape(secondaryX, ds);
if (isSecondaryBounded) cs.setSlice(secondaryStartIndex, secondaryEndIndex);
}
String label = DEFAULT_DISPLAY_DATA_SOURCE_ID? DataInfo.getAliasOrIdwithUnit(ds) : DataInfo.getAliasOrLabelwithUnit(ds);
if (primary) {
if (primaryCurves==null) primaryCurves = new Vector();
primaryCurves.add(cs);
insertCurve(cs, !usePrimaryX, false);
}
else {
setSecondaryAxis(false, true);
if (secondaryCurves==null) secondaryCurves = new Vector();
secondaryCurves.add(cs);
insertCurve(cs, !usePrimaryX, true);
}
if (_curves.size()>0) setLegendVisible(true);
setCurveLabel(cs, label);
setCurveColor(cs, defaultPalette[paletteIndex++]);
if (paletteIndex >= defaultPalette.length) paletteIndex = 0;
repaintDiagram(bounds);
return cs;
}
protected boolean addY(DataSource ds, boolean primary, boolean usePrimaryX, boolean background) {
if (ds==null) return false;
new LongAction(LongAction.LONG_ACTION_SHAPE | LongAction.LONG_ACTION_SOURCE,
new Object[]{ds, new Boolean(primary), new Boolean(usePrimaryX)},
new Object[]{ds, this} ) {
protected void doAction() {
doAddYAction((Object[])param);
}
}.start(background);
return !background;
}
/**
* Computes the "best" step to go from min to max
* Average number of graduations is set to 10
* Algo from simgo/util/geom/WaveAxis.java
*/
public static double computeStep(double min, double max,int averageNbGrad) {
// To understand the following, note that :
// Let x = ampli/(_averageNbGrad-1) .
// Let y = x/10^E(log10(x/0.75)) .
// Then: 0.75 <= y < 7.5
// Depending on the value of y, the graduations will be
// every 1, every 2 or every 5 ( times 10^n ).
double ampli = Math.abs(max - min);
if(averageNbGrad<=1){
averageNbGrad=10;
}
double x = ampli/(averageNbGrad-1);
double ln10 = Math.log(10);
double n = Math.floor(Math.log(x / 0.75)/ln10);
double zeros = Math.exp(n*ln10); // = 10^n
double y = x/zeros;
int roundVal = 2;
if(y<1.5) roundVal = 1;
else if(y>=3.5) roundVal = 5;
double ret=roundVal * zeros;
if(ret<1e-6){
return ret;
}
else{
return Math.rint(ret*1e6)/1e6;
}
}
public void repaintDiagram(Rectangle oldBounds) {
//Compute for PX
computeHorizontalBoundAndStep(axesLimitsArray[PX], primaryX, isPrimaryBounded);
if (axesLimitsArray[PX].validity){
setX(axesLimitsArray[PX].min, axesLimitsArray[PX].max, axesLimitsArray[PX].step);
}
setLabel(axesLimitsArray[PX].label,true,false);
//Compute for PY
computeVerticalBoundAndStep(axesLimitsArray[PY], primaryCurves);
if (axesLimitsArray[PY].validity){
setY(axesLimitsArray[PY].min, axesLimitsArray[PY].max, axesLimitsArray[PY].step);
}
setLabel(axesLimitsArray[PY].label,false,false);
//Compute for SX
computeHorizontalBoundAndStep(axesLimitsArray[SX], secondaryX, isSecondaryBounded);
if (axesLimitsArray[SX].validity){
setSecondaryX(axesLimitsArray[SX].min, axesLimitsArray[SX].max, axesLimitsArray[SX].step);
}
setLabel(axesLimitsArray[SX].label,true,true);
//Compute for SY
computeVerticalBoundAndStep(axesLimitsArray[SY], secondaryCurves);
if (axesLimitsArray[SY].validity){
setSecondaryY(axesLimitsArray[SY].min, axesLimitsArray[SY].max, axesLimitsArray[SY].step);
}
setLabel(axesLimitsArray[SY].label,false,true);
//Store bounds.
if (oldBounds!=null){
oldBounds.add(getBounds());
}
notifyChange(oldBounds);
}
/* (non-Javadoc)
* @see simtools.shapes.PlotShape#removeCurve(simtools.shapes.CurveShape)
*/
public void removeCurve(CurveShape curveShape){
super.removeCurve(curveShape);
if (primaryCurves!=null && primaryCurves.contains(curveShape)){
primaryCurves.remove(curveShape);
}else if (secondaryCurves!=null && secondaryCurves.contains(curveShape)){
secondaryCurves.remove(curveShape);
}
// Remove secondary Y axis if no more curves are displayed on it.
boolean displaySecondaryYaxis=false;
for(int i=0;i<_curves.size();i++){
displaySecondaryYaxis|=((Curve)_curves.get(i)).secondaryYaxis;
}
if (!displaySecondaryYaxis){
axesLimitsArray[SY].validity=false;
_asy2=null;
}
}
protected boolean canUseCurveSourcesMinMax(AxeRange xAxerange, CurveShape curveShape){
boolean res;
try {
res = (xAxerange.min <= curveShape.getXSource().getDoubleMin()) && (xAxerange.max >= curveShape.getXSource().getDoubleMax());
} catch (DataException e) {
res = false;
}
return res;
}
/**
* Auto-scale a vertical axe regarding values on
* @param axeRange - The range related to the axe to be scaled.
* @param curves - Curves that belong to that axe
*/
protected void computeVerticalBoundAndStep(AxeRange yAxeRange, Vector curves) {
if ((!yAxeRange.validity) && (curves!=null) && (curves.size()>0)) {
// Choice format is available only if all Y data sources can provide the same Choice format
ChoiceFormat format;
try {
format = ((CurveShape)curves.get(0)).getYSource().getChoiceFormat();
} catch (DataException e1) {
format = null;
}
yAxeRange.min= Double.POSITIVE_INFINITY;
yAxeRange.max= Double.NEGATIVE_INFINITY;
for(int i=0; i < curves.size(); i++) {
CurveShape curveShape = (CurveShape)curves.get(i);
AxeRange xAxerange = getCurve(curveShape).secondaryXaxis? axesLimitsArray[SX] : axesLimitsArray[PX];
boolean useYdataMinandMax = canUseCurveSourcesMinMax(xAxerange, curveShape);
try {
// When curve X range is not included into current X axis range, we have to compute the curve Y range related to X axis range
if (!useYdataMinandMax) {
curveShape.computeYLocalRange(xAxerange.min, xAxerange.max);
double curveYmin = curveShape.getLocalRangeMinPoint().y;
double curveYmax = curveShape.getLocalRangeMaxPoint().y;
if (curveYmin < yAxeRange.min) {
yAxeRange.min = curveYmin;
}
if (curveYmax > yAxeRange.max) {
yAxeRange.max = curveYmax;
}
}
} catch (DataException e) {
useYdataMinandMax = true;
}
// When curve X range is included into current X axis range, we can direct get curve Y mon and max from data source
try {
if (useYdataMinandMax) {
DataSource currentYSource = curveShape.getYSource();
double candidateMin = currentYSource.getDoubleMin();
double candidateMax = currentYSource.getDoubleMax();
if (candidateMin < yAxeRange.min){
yAxeRange.min = candidateMin;
}
if (candidateMax > yAxeRange.max){
yAxeRange.max = candidateMax;
}
}
// Update format
if (format!=null && !format.equals(curveShape.getYSource().getChoiceFormat())){
format = null;
}
} catch (DataException e) {
useYdataMinandMax = true;
}
}
// Update format
if(format!=null) {
// check if it is compatible
double[] limits=format.getLimits();
double lmin=limits[0];
double lmax=limits[limits.length-1];
double l=(lmax-lmin)/2;
if(lmin> yAxeRange.min && (lmin-yAxeRange.min)>l){
format=null;
} else if(lmax<yAxeRange.max && (yAxeRange.max-lmax)>l){
format=null;
} else {
yAxeRange.step=1;
}
}
if (yAxeRange.equals(axesLimitsArray[PY])) {
pyformat = format;
} else {
syformat = format;
}
// Floating axe
if (yAxeRange.floatingAxe) {
if (yAxeRange.max - yAxeRange.min > yAxeRange.floatingAxeRange){
yAxeRange.min = yAxeRange.max - yAxeRange.floatingAxeRange;
} else {
yAxeRange.max = yAxeRange.min + yAxeRange.floatingAxeRange;
}
}
// Compute step and validate axe range
yAxeRange.computeStep(nbYGraduation);
}
}
/**
* Method <b>computeHorizontalBoundAndStep</b>
* <br><b>Summary:</b><br>
* This method compute the bounds and the step of an horizontal axe.
* Parameters:
* @param axeRange The axe to set bounds and step.
* @param x The dataSource for the axe.
* @param isBounded Trus if the axe is bounded.
*
*/
private void computeHorizontalBoundAndStep(AxeRange axeRange, DataSource x, boolean isBounded) {
if ((!axeRange.validity) && (x!=null)) {
try {
if (isBounded) {
int order = x.sortedOrder();
if (order==1) {
axeRange.min = x.getDoubleValue(primaryStartIndex);
axeRange.max = x.getDoubleValue(primaryEndIndex);
}
else if (order==-1) {
axeRange.min = x.getDoubleValue(primaryEndIndex);
axeRange.max = x.getDoubleValue(primaryStartIndex);
}
else {
axeRange.min = x.getDoubleMin();
axeRange.max = x.getDoubleMax();
}
}
else {
axeRange.min = x.getDoubleMin();
axeRange.max = x.getDoubleMax();
}
if (axeRange.floatingAxe){
if (axeRange.max - axeRange.min > axeRange.floatingAxeRange){
axeRange.min = axeRange.max - axeRange.floatingAxeRange;
} else {
axeRange.max = axeRange.min + axeRange.floatingAxeRange;
}
}
//Compute the step of axeRange and validate axis
axeRange.computeStep(nbXGraduation);
}
catch (UnsupportedOperation uo) {} catch (DataException e) {
}
}
}
/* (non-Javadoc)
* @see jsynoptic.base.SelectionContextualActionProvider#getCollectiveActions()
*/
public LinkedHashMap getCollectiveActions(DiagramSelection sel, double x, double y, Object o, int context) {
LinkedHashMap res=new LinkedHashMap();
if (((primaryCurves!=null) && (primaryCurves.size()!=0))
|| ((secondaryCurves!=null) && (secondaryCurves.size()!=0))) { // do both primary and secondary
res.put(resources.getStringValue("autoscale"), null);
res.put(resources.getStringValue("autoscaleOnY"), null);
if (sel.getShapeCount() > 1) {
res.put(resources.getStringValue("adjustOnX") + ";" + resources.getStringValue("union"), null);
res.put(resources.getStringValue("adjustOnX") + ";" + resources.getStringValue("intersection"), null);
res.put(resources.getStringValue("adjustOnX") + ";" + resources.getStringValue("firstPlotSelected"), null);
}
}
if (o instanceof DataSource) {
res.put(resources.getStringValue("setX"), null);
}
return res;
}
public String[] getActions(double x, double y, Object o, int context) {
if (context==MOUSE_OVER_CONTEXT) {
return new String[] {"mouseOver"};
}
if (context==MOUSE_OUT_CONTEXT) {
return new String[] {"mouseOut"};
}
if (context==MOUSE_PRESSED_CONTEXT) {
MouseEvent e = (MouseEvent)o;
// Monitor left click
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != MouseEvent.BUTTON1_MASK)
return null;
return null;
}
Vector v = new Vector();
if (o instanceof DataSource) {
v.add(resources.getStringValue("setX"));
if (primaryX != null) {
v.add(resources.getStringValue("addY"));
v.add(resources.getStringValue("addSecY"));
v.add(resources.getStringValue("setSecX"));
if (secondaryX != null) {
v.add(resources.getStringValue("addYSecX"));
v.add(resources.getStringValue("addSecYSecX"));
}
}
} else if (o instanceof DataSourceCollection) {
v.add(resources.getStringValue("setXY1Yn"));
if (primaryX != null) {
v.add(resources.getStringValue("addY1Yn"));
v.add(resources.getStringValue("addSecY1Yn"));
v.add(resources.getStringValue("setSecXY1Yn"));
if (secondaryX != null)
v.add(resources.getStringValue("addSecY1YnForSecX"));
}
} else {
JSynoptic.setStatus(resources.getStringValue("noSource"));
}
if (context==EDITOR_CONTEXT) {
v.add(0,resources.getStringValue("properties"));
if (_curves.size()!=0){
v.add(0,resources.getStringValue("information"));
if (_magnetizedCurve != null) {
v.add(resources.getStringValue("selectPoint"));
v.add(resources.getStringValue("disableMagneticCoordinates") + _magnetizedCurve.getLabel());
}
for(int i=0;i<_curves.size();i++){
// magnetize a curve action
if (!((_magnetizedCurve!=null) && (((Curve)_curves.get(i)).equals(_magnetizedCurve)) ))
v.add(resources.getStringValue("enableMagneticCoordinates")+ ";" + ((Curve)_curves.get(i)).getLabel() );
}
for(int i=0;i<_curves.size();i++){
// Delete curve action
v.add(resources.getStringValue("deleteCurve")+ ";" + ((Curve)_curves.get(i)).getLabel() );
}
}
}
return (String[])v.toArray(new String[v.size()]);
}
public boolean canDoAction(double x, double y, Object o, String action, int context) {
return true;
}
public void displayCursorLocation(double x, double y){
String msg = "";
if (_magnetizedCurve!=null){
CurvePoint currentPoint = _magnetizedCurve.shape.getCurrentPoint();
msg += _magnetizedCurve.getLabel() + ": ";
msg += " x = " + currentPoint.x;
msg += ", y = " + currentPoint.y;
msg += " --- Slope : ";
msg += " x = " + currentPoint.slop_x;
msg += ", y = " + currentPoint.slop_y;
CurvePoint refPoint = _magnetizedCurve.shape.getReferencePoint();
if (refPoint != null){
msg += " --- Delta from tagged point : ";
msg += " x = " + (currentPoint.x - refPoint.x);
msg += ", y = " + (currentPoint.y - refPoint.y);
}
} else {
if (_asx1!=null) {
if (axesLimitsArray[PX].label!=null) msg += axesLimitsArray[PX].label;
else msg+= "x";
msg += "=" + AxisLabelFormatter.labelFormat(_asx1.getMin() + (x - _ox) / _asx1.getScale());
}
if (_asy1!=null) {
if (!msg.equals("")) msg+=" ";
if (axesLimitsArray[PY].label!=null) msg += axesLimitsArray[PY].label;
else msg+= "y";
msg += "=" + AxisLabelFormatter.labelFormat(_asy1.getMin() + (_oy - y) / _asy1.getScale());
}
if (_asx2!=null) {
if (!msg.equals("")) msg+=" ";
if (axesLimitsArray[SX].label!=null) msg += axesLimitsArray[SX].label;
else msg+= "x'";
msg += "=" + AxisLabelFormatter.labelFormat(_asx2.getMin() + (x - _ox) / _asx2.getScale());
}
if (_asy2!=null) {
if (!msg.equals("")) msg+=" ";
if (axesLimitsArray[SY].label!=null) msg += axesLimitsArray[SY].label;
else msg+= "y'";
msg += "=" + AxisLabelFormatter.labelFormat(_asy2.getMin() + (_oy - y) / _asy2.getScale());
}
}
if (!msg.equals("")) JSynoptic.setStatus(msg);
}
/* (non-Javadoc)
* @see jsynoptic.base.SelectionContextualActionProvider#doAction(simtools.diagram.DiagramSelection, double, double, java.lang.Object, java.lang.String, javax.swing.undo.CompoundEdit)
*/
public boolean doCollectiveAction(DiagramSelection sel, double x, double y, Object o, String action, CompoundEdit undoableEdit){
boolean res = false;
boolean canDoAction = true;
Vector v = sel.getSelectedElements();
if (!v.isEmpty()) {
if (action.startsWith(resources.getStringValue("adjustOnX"))) { // compute the collective X primary and secondary ranges
double pxmin=0, pxmax=0, sxmin=0, sxmax=0;
// Get current selected plot X range
Plot firstPlot = null;
for (int i = 0; i < sel.getShapeCount() && firstPlot == null; i++) {
Shape s = sel.getShape(i);
if ((s.contains(x,y)) && (s instanceof Plot) ){
firstPlot = (Plot)s;
}
}
if (firstPlot == null) {
canDoAction = false;
} else {
pxmin = firstPlot._asx1.getMin();
pxmax = firstPlot._asx1.getMax();
boolean adjustSecondaryXRange = (_asx2 != null);
if (adjustSecondaryXRange){
sxmin = firstPlot._asx2.getMin();
sxmax = firstPlot._asx2.getMax();
}
// loop on other selected plots
if (! action.equals(resources.getStringValue("adjustOnX") + ";" + resources.getStringValue("firstPlotSelected"))){
boolean isUnion = action.equals(resources.getStringValue("adjustOnX") + ";" + resources.getStringValue("union"));
for(int i=0; i < v.size(); i++) {
Plot plot = (Plot)v.get(i);
if (isUnion){
pxmin = Math.min(pxmin, plot._asx1.getMin());
pxmax = Math.max(pxmax, plot._asx1.getMax());
} else {
pxmin = Math.max(pxmin, plot._asx1.getMin());
pxmax = Math.min(pxmax, plot._asx1.getMax());
}
adjustSecondaryXRange &= (plot._asx2 != null);
if (adjustSecondaryXRange){
if (isUnion){
sxmin = Math.min(sxmin, plot._asx2.getMin());
sxmax = Math.max(sxmax, plot._asx2.getMax());
} else {
sxmin = Math.max(sxmin, plot._asx2.getMin());
sxmax = Math.min(sxmax, plot._asx2.getMax());
}
}
}
}
if ( (pxmin >= pxmax) || ( adjustSecondaryXRange && (sxmin >= sxmax))){
canDoAction = false; // cannot set such an X range
} else {
o = new Double[4];
((Double[])o)[0] = new Double(pxmin);
((Double[])o)[1] = new Double(pxmax);
((Double[])o)[2] = adjustSecondaryXRange? new Double(sxmin) : null;
((Double[])o)[3] = adjustSecondaryXRange? new Double(sxmax) : null;
}
}
}
// Do action on selection
if (canDoAction){
res = true;
for(int i=0; i < v.size(); i++) {
Object element = v.get(i);
if (element instanceof Plot){
res &= ((Plot)element).doAction(x, y,o, action, undoableEdit);
}
}
}
}
return res;
}
public boolean doAction(double x, double y, Object o, String action, CompoundEdit undoableEdit) {
if (action==null) return false;
if (action.equals("mouseOver")) {
if (_magnetizedCurve!=null){
AxisShape axe_x = _magnetizedCurve.secondaryXaxis? _asx2 : _asx1;
double pos_x = axe_x.getMin() + (x - _ox) / axe_x.getScale();
try{
_magnetizedCurve.shape.setCurrentPoint(pos_x);
// Display red circle on magnetized point coordinates :
notifyChange(getBounds());
}catch (DataException e){
JSynoptic.setStatus("This curve cannot be magnetized");
}
}
displayCursorLocation(x,y);
return true;
}
if (action.equals("mouseOut")) {
JSynoptic.setStatus("");
return true;
}
if (action.equals( resources.getStringValue("selectPoint"))) {
_magnetizedCurve.shape.setReferencePoint(_magnetizedCurve.shape.getCurrentPoint());
repaintDiagram(getBounds());
return true;
}
if (action.equals(resources.getStringValue("information"))) {
PlotInformationDialog di = new PlotInformationDialog(this);
JDialog jd = di.createDialog(JSynoptic.gui.getOwner());
if (jd!=null) jd.show();
return true;
}
for(int i=0;i<_curves.size();i++){
// magnetize a curve action
if (action.equals(resources.getStringValue("enableMagneticCoordinates") + ";" +((Curve)_curves.get(i)).getLabel())){
_magnetizedCurve = (Curve)_curves.get(i);
return true;
}
// Delete a curve action
if (action.equals(resources.getStringValue("deleteCurve") + ";" +((Curve)_curves.get(i)).getLabel())){
HashMap oldValues = getCurvesProperties(null);
removeCurve(((Curve)_curves.get(i)).shape);
repaintDiagram(getBounds());
PlotCompoundEdit ce=new PlotCompoundEdit(oldValues);
if(undoableEdit != null){
undoableEdit.addEdit(ce);
}
return true;
}
}
if (( _magnetizedCurve!=null) && action.equals(resources.getStringValue("disableMagneticCoordinates") + _magnetizedCurve.getLabel())) {
_magnetizedCurve.shape.setReferencePoint(null);
_magnetizedCurve=null;
repaintDiagram(getBounds());
return true;
}
if (action.equals(resources.getStringValue("properties"))) {
new LongAction(LongAction.LONG_ACTION_SHAPE, null, this) {
protected void doAction() {
JPropertiesPanel panel=createPanel();
/** Only one shape properties dialog box can be displayed at once
* When user opens a dialog box properties while another one is still displayed: this last dislaog box is closed
*/
Point oldLocation=null;
if (currentDialogBox!=null){
oldLocation= currentDialogBox.getBounds().getLocation();
currentDialogBox.dispose();
}
ArrayList shapes = new ArrayList();
shapes.add(Plot.this);
PlotPropertiesDialogBox optionDialog = new PlotPropertiesDialogBox(JSynoptic.gui.getOwner(), panel, panel.getShapeName(), shapes);
if (oldLocation!=null)
optionDialog.setLocation(oldLocation);
currentDialogBox = optionDialog;
optionDialog.show();
}
}.start();
return true;
}
if (action.startsWith(resources.getStringValue("adjustOnX"))) {
if (o instanceof Double[]){
HashMap oldValues=getAxesProperties(null, -1);
Double[] xranges = ((Double[])o);
axesLimitsArray[PX].min = xranges[0].doubleValue();
axesLimitsArray[PX].max = xranges[1].doubleValue();
axesLimitsArray[PX].step = computeStep(axesLimitsArray[PX].min, axesLimitsArray[PX].max, preferredXGraduation);
if ( (xranges[2] != null) && (_asx2 != null)) {
axesLimitsArray[SX].min = xranges[2].doubleValue();
axesLimitsArray[SX].max = xranges[3].doubleValue();
axesLimitsArray[SX].step = computeStep(axesLimitsArray[SX].min, axesLimitsArray[SX].max, preferredXGraduation);
}
repaintDiagram(getBounds());
PlotCompoundEdit ce=new PlotCompoundEdit(oldValues);
if(undoableEdit != null){
undoableEdit.addEdit(ce);
}
return true;
} else {
return false;
}
}
if (action.equals(resources.getStringValue("autoscale"))) {
// get the old values for the 4 axes
HashMap oldValues=getAxesProperties(null, -1);
for(int i =0; i< AXE_NUMBER;i++){
axesLimitsArray[i].validity = false;
}
repaintDiagram(getBounds());
PlotCompoundEdit ce=new PlotCompoundEdit(oldValues);
if(undoableEdit != null){
undoableEdit.addEdit(ce);
}
return true;
}
if (action.equals(resources.getStringValue("autoscaleOnY"))) {
// get the old values for the 4 axes
HashMap oldValues=getAxesProperties(null, -1);
// auto-scale on primary Y
axesLimitsArray[PY].validity = false;
// auto-scale on secondary Y
axesLimitsArray[SY].validity = false;
repaintDiagram(getBounds());
PlotCompoundEdit ce=new PlotCompoundEdit(oldValues);
if(undoableEdit != null){
undoableEdit.addEdit(ce);
}
return true;
}
if (o instanceof DataSource) {
boolean res = false;
DataSource ds = (DataSource)o;
if (action.equals(resources.getStringValue("setX"))) {
res = setPrimaryX(ds, true);
}
if (action.equals(resources.getStringValue("addY"))) {
res = addPrimaryY(ds, true);
}
if (action.equals(resources.getStringValue("addYSecX"))) {
res = addPrimaryYForSecondaryX(ds, true);
}
if (action.equals(resources.getStringValue("addSecY"))) {
res = addSecondaryY(ds, true);
}
if (action.equals(resources.getStringValue("setSecX"))) {
res = setSecondaryX(ds, true);
}
if (action.equals(resources.getStringValue("addSecYSecX"))) {
res = addSecondaryYForSecondaryX(ds, true);
}
return res;
}
if (o instanceof DataSourceCollection) {
DataSourceCollection dsc = (DataSourceCollection)o;
if (action.equals(resources.getStringValue("setXY1Yn"))) {
if (dsc.size()<1) return false;
new LongAction(0, new Object[] {dsc,action}) {
protected void doAction() {
DataSourceCollection dsc = (DataSourceCollection)((Object[])param)[0];
setPrimaryX((DataSource)dsc.get(0), false);
boolean hasValues = axesLimitsArray[PY].validity;
axesLimitsArray[PY].validity = true; // compute only once all curve are inserted
for (int i=1; i<dsc.size()-1; i++)
addPrimaryY((DataSource)dsc.get(i), false);
axesLimitsArray[PY].validity = hasValues;
if (dsc.size()>1) addPrimaryY((DataSource)dsc.get(dsc.size()-1), false);
Rectangle bounds = getBounds();
setTitle(DataInfo.getLabel(dsc));
repaintDiagram(bounds);
}
}.start();
return false;
}
if (action.equals(resources.getStringValue("addY1Yn"))) {
if (dsc.size()<1) return false;
new LongAction(0, new Object[] {dsc,action}) {
protected void doAction() {
DataSourceCollection dsc = (DataSourceCollection)((Object[])param)[0];
boolean hasValues = axesLimitsArray[PY].validity;
axesLimitsArray[PY].validity = true; // compute only once all curve are inserted
for (int i=0; i<dsc.size()-1; i++)
addPrimaryY((DataSource)dsc.get(i), false);
axesLimitsArray[PY].validity = hasValues;
if (dsc.size()>0) addPrimaryY((DataSource)dsc.get(dsc.size()-1), false);
Rectangle bounds = getBounds();
repaintDiagram(bounds);
}
}.start();
return false;
}
if (action.equals(resources.getStringValue("addSecY1Yn"))) {
if (dsc.size()<1) return false;
new LongAction(0, new Object[] {dsc,action}) {
protected void doAction() {
DataSourceCollection dsc = (DataSourceCollection)((Object[])param)[0];
boolean hasValues = axesLimitsArray[SY].validity;
boolean hasLabel = (axesLimitsArray[SY].label!=null);
axesLimitsArray[SY].validity = true; // compute only once all curve are inserted
for (int i=0; i<dsc.size()-1; i++)
addSecondaryY((DataSource)dsc.get(i), false);
axesLimitsArray[SY].validity = hasValues;
if (dsc.size()>0) addSecondaryY((DataSource)dsc.get(dsc.size()-1), false);
Rectangle bounds = getBounds();
if ((!hasLabel) && (dsc.size()>1)) {axesLimitsArray[SY].label = null; setLegendVisible(true);}
repaintDiagram(bounds);
}
}.start();
return false;
}
if (action.equals(resources.getStringValue("setSecXY1Yn"))) {
if (dsc.size()<1) return false;
new LongAction(0, new Object[] {dsc,action}) {
protected void doAction() {
DataSourceCollection dsc = (DataSourceCollection)((Object[])param)[0];
setSecondaryX((DataSource)dsc.get(0), false);
boolean hasValues = axesLimitsArray[SY].validity;
boolean hasLabel = (axesLimitsArray[SY].label!=null);
axesLimitsArray[SY].validity = true; // compute only once all curve are inserted
for (int i=1; i<dsc.size()-1; i++)
addSecondaryY((DataSource)dsc.get(i), false);
axesLimitsArray[SY].validity = hasValues;
if (dsc.size()>1) addSecondaryY((DataSource)dsc.get(dsc.size()-1), false);
Rectangle bounds = getBounds();
if ((!hasLabel) && (dsc.size()>2)) {axesLimitsArray[SY].label = null; setLegendVisible(true);}
repaintDiagram(bounds);
}
}.start();
return false;
}
if (action.equals(resources.getStringValue("addSecY1YnForSecX"))) {
if (dsc.size()<1) return false;
new LongAction(0, new Object[] {dsc,action}) {
protected void doAction() {
DataSourceCollection dsc = (DataSourceCollection)((Object[])param)[0];
boolean hasValues = axesLimitsArray[SY].validity;
boolean hasLabel = (axesLimitsArray[SY].label!=null);
axesLimitsArray[SY].validity = true; // compute only once all curve are inserted
for (int i=0; i<dsc.size()-1; i++)
addSecondaryYForSecondaryX((DataSource)dsc.get(i), false);
axesLimitsArray[SY].validity = hasValues;
if (dsc.size()>0) addSecondaryYForSecondaryX((DataSource)dsc.get(dsc.size()-1), false);
Rectangle bounds = getBounds();
if ((!hasLabel) && (dsc.size()>1)) {axesLimitsArray[SY].label = null; setLegendVisible(true);}
repaintDiagram(bounds);
}
}.start();
return false;
}
}
return false;
}
/**
* Changes the axes defintion according to a zoom defined with 2 coordinates
* @param x1 The first zoom area x coordinate.
* @param x2 The second zoom area x coordinate.
* @param y1 The first zoom area y coordinate.
* @param y2 The second zoom area y coordinate.
* @param xOnly True zoom only the X axis
*/
public void zoom(double x1, double x2, double y1, double y2, boolean xOnly){
if (_asx1 != null) {
computeHorizontalAxeRange(axesLimitsArray[PX], _asx1, logpx, x1, x2);
axesLimitsArray[PX].validity = true;
} else {
axesLimitsArray[PX].validity = false;
}
if(!xOnly){
if (_asy1 != null) {
computeVerticalAxeRange(axesLimitsArray[PY], _asy1, logpy, y1, y2);
axesLimitsArray[PY].validity = true;
} else {
axesLimitsArray[PY].validity = false;
}
}
if (_asx2 != null) {
computeHorizontalAxeRange(axesLimitsArray[SX], _asx2, logsx, x1, x2);
axesLimitsArray[SX].validity = true;
} else {
axesLimitsArray[SX].validity = false;
}
if(!xOnly){
if (_asy2 != null) {
computeVerticalAxeRange(axesLimitsArray[SY], _asy2, logsy, y1, y2);
axesLimitsArray[SY].validity = true;
} else {
axesLimitsArray[SY].validity = false;
}
}
}
/**
* Make a zoom box around (x,y) position.
* @param x
* @param y
* @param zoomWheelFactor
* @param zoomIn, if true zoom in , otherwise zoom out
*/
public void zoomWheel(double x, double y, double zoomWheelFactor, boolean zoomIn){
if (_asx1 != null) {
computeZoomWheelHorizontalAxeRange(axesLimitsArray[PX], _asx1, logpx, x, zoomIn,zoomWheelFactor);
axesLimitsArray[PX].validity = true;
} else {
axesLimitsArray[PX].validity = false;
}
if (_asy1 != null) {
computeZoomWheelVerticalAxeRange(axesLimitsArray[PY], _asy1, logpy, y, zoomIn,zoomWheelFactor);
axesLimitsArray[PY].validity = true;
} else {
axesLimitsArray[PY].validity = false;
}
if (_asx2 != null) {
computeZoomWheelHorizontalAxeRange(axesLimitsArray[SX], _asx2, logsx, x, zoomIn,zoomWheelFactor);
axesLimitsArray[SX].validity = true;
} else {
axesLimitsArray[SX].validity = false;
}
if (_asy2 != null) {
computeZoomWheelVerticalAxeRange(axesLimitsArray[SY], _asy2, logsy, y, zoomIn,zoomWheelFactor);
axesLimitsArray[SY].validity = true;
} else {
axesLimitsArray[SY].validity = false;
}
}
/**
* Changes the axes defintion according to a translation defined with 2 points
* @param x1 The first translation point x coordinate.
* @param x2 The second translation point x coordinate.
* @param y1 The first translation point y coordinate.
* @param y2 The second translation point y coordinate.
*/
public void translate(double x1, double x2, double y1, double y2){
if (_asx1 != null) {
computeTranslationAxeRange(axesLimitsArray[PX], _asx1, logpx, x1- x2);
axesLimitsArray[PX].validity = true;
} else {
axesLimitsArray[PX].validity = false;
}
if (_asy1 != null) {
computeTranslationAxeRange(axesLimitsArray[PY], _asy1, logpy, y2- y1);
axesLimitsArray[PY].validity = true;
} else {
axesLimitsArray[PY].validity = false;
}
if (_asx2 != null) {
computeTranslationAxeRange(axesLimitsArray[SX], _asx2, logsx, x1-x2);
axesLimitsArray[SX].validity = true;
} else {
axesLimitsArray[SX].validity = false;
}
if (_asy2 != null) {
computeTranslationAxeRange(axesLimitsArray[SY], _asy2, logsy, y2 - y1);
axesLimitsArray[SY].validity = true;
} else {
axesLimitsArray[SY].validity = false;
}
}
/**
* Computes a zoom for an vertical axis (PY or SY).
* @param axeRange The <b>AxeRange</b> axeRange to compute.
* @param axe The <b>AxisShape</b> that use this AxeRange.
* @param log True if the axe is under log format, false otherwise.
* @param y1 The first zoom area y coordinate.
* @param y2 The second zoom area y coordinate.
*/
protected void computeVerticalAxeRange(AxeRange axeRange, AxisShape axe,
boolean log, double y1, double y2) {
double v1 = axe.getMin() + ((_oy - Math.min(y1, y2)) / axe.getScale());
double v2 = axe.getMin() + ((_oy - Math.max(y1, y2)) / axe.getScale());
double vmax = (v2>v1)? v2 : v1;
double vmin = (v2>v1)? v1 : v2;
if (log) {
axeRange.max = Math.pow(10, Math.ceil(vmax));
axeRange.min = Math.pow(10, Math.floor(vmin));
} else {
axeRange.min = vmin;
axeRange.max = vmax;
// Compute the step of axeRange, and re-evaluate bounds.
axeRange.computeStep(nbYGraduation);
}
}
/**
* Computes a zoom for an horizontal axis (PX or SX). Parameters:
* @param axeRange The <b>AxeRange</b> axeRange to compute.
* @param axe The <b>AxisShape</b> that use this AxeRange.
* @param log True if the axe is under log format, false otherwise.
* @param x1 The first zoom area x coordinate.
* @param x2 The second zoom area x coordinate.
*/
protected void computeHorizontalAxeRange(AxeRange axeRange, AxisShape axe,
boolean log, double x1, double x2) {
double v1 = axe.getMin() + (Math.min(x1, x2) -_ox) / axe.getScale();
double v2 = axe.getMin() + (Math.max(x1, x2) -_ox) / axe.getScale();
double vmax = (v2>v1)? v2 : v1;
double vmin = (v2>v1)? v1 : v2;
if (log) {
axeRange.min = Math.pow(10, Math.floor(vmin));
axeRange.max = Math.pow(10, Math.ceil(vmax));
} else {
axeRange.min = vmin;
axeRange.max = vmax;
axeRange.computeStep(nbXGraduation);
}
}
/**
* Computes an axis coordinate from a mouse position in plot shape
* @param axe The <b>AxisShape</b>
* @param x1 A mouse position in plot hsape.
* @return computed axis coordinate
*/
public Double getAxeValue(int axeIndex, int x){
AxisShape axe=null;
switch (axeIndex){
case Plot.PX: axe = _asx1; break;
case Plot.SX: axe = _asx2; break;
case Plot.PY: axe = _asy1; break;
case Plot.SY: axe = _asy2; break;
}
Double ret=null;
if (axe!=null){
if (axe!=null){
double anchor = axe.isVertical()? _oy : _ox;
double value = axe.getMin() + (x - anchor) / axe.getScale();
if (axe.isLog()) {
value = Math.pow(10, Math.floor(value));
}
ret = new Double(value);
}
}
return ret;
}
/**
* Computes a translation for an axis (PX or SX). Parameters:
* @param axeRange The <b>AxeRange</b> axeRange to compute.
* @param axe The <b>AxisShape</b> that use this AxeRange.
* @param log True if the axe is under log format, false otherwise.
* @param x1 The translation value
*/
protected void computeTranslationAxeRange(AxeRange axeRange, AxisShape axe,
boolean log, double x) {
double v =x / axe.getScale();
if (log) {
double logmin = Math.log(axeRange.min) + v;
double logmax = Math.log(axeRange.max) + v;
axeRange.min = Math.pow(10, Math.floor(logmin));
axeRange.max = Math.pow(10, Math.ceil(logmax));
} else {
axeRange.min += v;
axeRange.max += v;
axeRange.computeStep(nbXGraduation);
}
}
protected void computeZoomWheelHorizontalAxeRange(AxeRange axeRange, AxisShape axe,
boolean log, double x, boolean zoomIn, double zoomWheelFactor) {
double v = axe.getMin() + (x - _ox ) / axe.getScale();
double l = axeRange.max - axeRange.min;
if (zoomIn)
l/=zoomWheelFactor;
else
l*=zoomWheelFactor;
if (log) {
//TODO
axeRange.min = Math.pow(10, Math.floor(v));
axeRange.max = Math.pow(10, Math.ceil(v));
} else {
double ratio = (v - axeRange.min) / (axeRange.max - axeRange.min);
axeRange.min = v - l*ratio;
axeRange.max = v + l*(1-ratio);
axeRange.computeStep(nbXGraduation);
}
}
protected void computeZoomWheelVerticalAxeRange(AxeRange axeRange, AxisShape axe,
boolean log, double y, boolean zoomIn, double zoomWheelFactor) {
double v = axe.getMin() + (_oy- y) / axe.getScale();
double l = axeRange.max - axeRange.min;
if (zoomIn)
l/=zoomWheelFactor;
else
l*=zoomWheelFactor;
if (log) {
//TODO
axeRange.min = Math.pow(10, Math.floor(v));
axeRange.max = Math.pow(10, Math.ceil(v));
} else {
double ratio = (v - axeRange.min) / (axeRange.max - axeRange.min);
axeRange.min = v - l*ratio;
axeRange.max = v + l*(1-ratio);
axeRange.computeStep(nbYGraduation);
}
}
/* (non-Javadoc)
* @see jsynoptic.base.DataSourceConsumer#addDataSource(simtools.data.DataSource)
*/
public boolean addDataSource(DataSource d) {
if(primaryX==null){
setPrimaryX(d, true);
}
else{
addPrimaryY(d,true);
}
return true;
}
/* (non-Javadoc)
* @see jsynoptic.base.DataSourceConsumer#canAddDataSource(simtools.data.DataSource)
*/
public boolean canAddDataSource(DataSource d) {
return true;
}
// Inner classes
/* (non-Javadoc)
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
// listener override to benefit from optimisation
public void notificationEnd(Object referer) {
if (axesLimitsArray==null || axesLimitsArray[SY]==null) {
// may occur during deserialization
// because PlotShape upper class desrialization restores
// data sources and the related listeners before the end
// of the deserialization of Plot object
// TODO find a more generic and more accurate solution
return;
}
if(axesLimitsArray[PX].auto){
axesLimitsArray[PX].validity = false;
}
if(axesLimitsArray[PY].auto){
axesLimitsArray[PY].validity = false;
}
if(axesLimitsArray[SX].auto){
axesLimitsArray[SX].validity = false;
}
if(axesLimitsArray[SY].auto){
axesLimitsArray[SY].validity = false;
}
if (primaryX != null) {
try {
primaryStartIndex = primaryX.getStartIndex();
} catch (UnsupportedOperation e) {
}
try {
primaryEndIndex = primaryX.getLastIndex();
} catch (UnsupportedOperation e) {
}
}
if (secondaryX != null) {
try {
secondaryStartIndex = secondaryX.getStartIndex();
} catch (UnsupportedOperation e) {
}
try {
secondaryEndIndex = secondaryX.getLastIndex();
} catch (UnsupportedOperation e) {
}
}
isNotifying = false;
super.notificationEnd(referer);
isNotifying = true;
repaintDiagram(getBounds());
}
// hack to avoid double parent notification, see notificationEnd
protected transient boolean isNotifying = true;
protected synchronized void notifyChange() {
if (isNotifying) super.notifyChange();
}
public void shapeDataChanged(CurveShape csc, DataSource oldData, DataSource newData, boolean onX) {
super.shapeDataChanged(csc, oldData, newData, onX);
if (primaryCurves!=null && onX) {
for (Iterator it = primaryCurves.iterator(); it.hasNext(); ) {
CurveShape cs = (CurveShape)it.next();
if (csc==cs){
if(primaryX == oldData) {
primaryX=newData;
if (isPrimaryBounded && (primaryX!=null)) {
try {
long imin = primaryX.getStartIndex();
long imax = primaryX.getLastIndex();
if (imin>primaryStartIndex) primaryStartIndex = imin;
if (imax<primaryEndIndex) primaryEndIndex = imax;
}
catch (UnsupportedOperation uo1) {
isPrimaryBounded = false;
}
}
}
}
}
}
if (secondaryCurves!=null && onX) {
for (Iterator it = secondaryCurves.iterator(); it.hasNext(); ) {
CurveShape cs = (CurveShape)it.next();
if (csc==cs){
if(secondaryX == oldData) {
secondaryX=newData;
if (isSecondaryBounded && (secondaryX!=null)) {
try {
long imin = secondaryX.getStartIndex();
long imax = secondaryX.getLastIndex();
if (imin>secondaryStartIndex) secondaryStartIndex = imin;
if (imax<secondaryEndIndex) secondaryEndIndex = imax;
}
catch (UnsupportedOperation uo2) {
isSecondaryBounded = false;
}
}
}
}
}
}
}
// Take care of serialisation. Special handling for datasources
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
out.defaultWriteObject();
DataSourcePool.global.writeDataSource(out, primaryX);
DataSourcePool.global.writeDataSource(out, secondaryX);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
primaryX = DataSourcePool.global.readDataSource(in);
secondaryX = DataSourcePool.global.readDataSource(in);
nbXGraduation = preferredXGraduation;
nbYGraduation = preferredYGraduation;
if (isPrimaryBounded && (primaryX!=null)) {
try {
primaryStartIndex = primaryX.computeStartIndex();
primaryEndIndex = primaryX.computeLastIndex();
}
catch (UnsupportedOperation uo1) {
isPrimaryBounded = false;
}
}
if (isSecondaryBounded && (secondaryX!=null)) {
try {
secondaryStartIndex = secondaryX.computeStartIndex();
secondaryEndIndex = secondaryX.computeLastIndex();
}
catch (UnsupportedOperation uo2) {
isSecondaryBounded = false;
}
}
isNotifying = true;
// fix old bugs on cloned plots
for(int k=0;k<2;k++){
Vector curves=(k==0) ? primaryCurves : secondaryCurves;
if (curves != null) {
for (int i = 0; i < curves.size(); i++) {
CurveShape cs = (CurveShape) curves.get(i);
Curve c = getCurve(cs);
if (c == null) {
System.err.print("Try to fix wrong curve shape ...");
for (int j = 0; j < _curves.size(); j++) {
c = (Curve) _curves.get(j);
try{
if ((c.shape.getXSource() == cs.getXSource())
&& (c.shape.getYSource() == cs.getYSource())) {
c.shape = cs;
System.err.print(" OK");
break;
}
}catch (DataException e){}
}
System.err.println("");
}
}
}
}
// Update curves label in case display label mode has changed
for (int i=0;i<_curves.size();i++){
CurveShape curveShape = ((Curve)_curves.get(i)).shape;
try{
DataSource ds= curveShape.getYSource();
if (ds != null) {
String label = DEFAULT_DISPLAY_DATA_SOURCE_ID? DataInfo.getAliasOrIdwithUnit(ds) : DataInfo.getAliasOrLabelwithUnit(ds);
setCurveLabel(curveShape,label);
}
}catch (DataException e){}
}
// X axis legends
if (primaryX != null){
String label = DEFAULT_DISPLAY_DATA_SOURCE_ID? DataInfo.getAliasOrIdwithUnit(primaryX) : DataInfo.getAliasOrLabelwithUnit(primaryX);
axesLimitsArray[PX].label = label;
}
if (secondaryX != null){
String label = DEFAULT_DISPLAY_DATA_SOURCE_ID? DataInfo.getAliasOrIdwithUnit(secondaryX) : DataInfo.getAliasOrLabelwithUnit(secondaryX);
axesLimitsArray[SX].label = label;
}
//Check for axeRange evolution.
if(axesLimitsArray == null || axesLimitsArray[0] == null || !axesLimitsArray[0].created){
//If first axe limit has not been created, it means, we have restored a file
// That is prior to axeLimit introduction.
//Do the transformation
axesLimitsArray = new AxeRange[AXE_NUMBER];
//Set PX AxeRange.
axesLimitsArray[PX] = new AxeRange(pxmin, pxmax, pxstep, pxvaluesOK, autopx, pxlabel);
//Set PY AxeRange.
axesLimitsArray[PY] = new AxeRange(pymin, pymax, pystep, pyvaluesOK, autopy, pylabel);
//Set SX AxeRange.
axesLimitsArray[SX] = new AxeRange(sxmin, sxmax, sxstep, sxvaluesOK, autosx, sxlabel);
//Set SY AxeRange.
axesLimitsArray[SY] = new AxeRange(symin, symax, systep, syvaluesOK, autosy, sylabel);
}
}
//-----------------------------------------------------------------------------
// Properties managment
//-----------------------------------------------------------------------------
public JPropertiesPanel createPanel() {
int curvesSize = ((primaryCurves!=null ? primaryCurves.size() : 0) + (secondaryCurves!=null ? secondaryCurves.size() : 0));
return new PlotPropertiesPanel(curvesSize, Builtin.resources.getString("Plot"));
}
public String[] getPropertyNames(){
if (_propertyNames==null)
_propertyNames = new PlotPropertiesNames().getPropertyNames();
return _propertyNames;
}
public static class PlotPropertiesNames extends AbstractShapePropertiesNames{
public PlotPropertiesNames(){
super();
// four axes
propertyNames.addAll(Arrays.asList(new AxePropertiesNames("primX").getPropertyNames()));
propertyNames.addAll(Arrays.asList(new AxePropertiesNames("primY").getPropertyNames()));
propertyNames.addAll(Arrays.asList(new AxePropertiesNames("secX").getPropertyNames()));
propertyNames.addAll(Arrays.asList(new AxePropertiesNames("secY").getPropertyNames()));
// curves
propertyNames.addAll(Arrays.asList((new CurveShapePropertiesNames()).getPropertyNames()));
// limits
propertyNames.addAll(Arrays.asList((new LimitShapePropertiesNames()).getPropertyNames()));
propertyNames.add("PLOT_LEGEND");
propertyNames.add("PLOT_TITLE");
propertyNames.add("PLOT_CURVE_INFORMATION");
}
}
public HashMap getAxesProperties(HashMap map, int axeNumber){
String[] list=getPropertyNames();
HashMap res=(map == null) ? new HashMap() : map;
if (list!=null){
for(int i=0;i<list.length;i++){
if(list[i].startsWith("PLOT_AXE_")
&& (list[i].indexOf("_MAX")>0
|| list[i].indexOf("_MIN")>0
|| list[i].indexOf("_STEP")>0)
&& (axeNumber==-1
|| list[i].indexOf(AXIS_ID[axeNumber])>0)){
res.put(list[i],getPropertyValue(list[i]));
}
}
}
return res;
}
public HashMap getCurvesProperties(HashMap map){
HashMap res=(map == null) ? new HashMap() : map;
Vector curves= new Vector();
if (primaryCurves!=null)
curves.addAll(primaryCurves);
if (secondaryCurves!=null)
curves.addAll(secondaryCurves);
res.put("PLOT_CURVE_LIST", getCurveParametersList(curves));
return res;
}
public void setPropertyValue(String name, Object value) {
super.setPropertyValue(name, value);
if (name.equalsIgnoreCase("PLOT_TITLE")) {
if(value instanceof String){
setTitle((String) value);
}
else{
setTitle(null);
}
}
else if (name.equalsIgnoreCase("PLOT_CURVE_INFORMATION")&& (value instanceof Boolean)) {
setCurveInformationVisible((Boolean)value);
}
else if (name.equalsIgnoreCase("PLOT_LEGEND")&& (value instanceof Boolean)) {
setLegendVisible(((Boolean)value).booleanValue());
}
else if(name.startsWith("PLOT_AXE_")){
boolean vb;
double vd;
String vs;
for(int i=0;i<AXIS_ID.length;i++){
if(name.startsWith(AxisShape.getPrefix(AXIS_ID[i]))){
if (name.endsWith("_OK") && (value instanceof Boolean)) {
vb=((Boolean)value).booleanValue();
axesLimitsArray[i].validity=vb;
}
else if (name.endsWith("_GRID") && (value instanceof Boolean)) {
vb=((Boolean)value).booleanValue();
if(i==0 && _asx1!=null) _asx1.setWithGridlines(vb);
else if(i==1 && _asy1!=null) _asy1.setWithGridlines(vb);
else if(i==2 && _asx2!=null) _asx2.setWithGridlines(vb);
else if(_asy2!=null) _asy2.setWithGridlines(vb);
}
else if (name.endsWith("_DASHEDGRID") && (value instanceof Boolean)) {
vb=((Boolean)value).booleanValue();
if(i==0 && _asx1!=null) _asx1.setWithDashedGrid(vb);
else if(i==1 && _asy1!=null) _asy1.setWithDashedGrid(vb);
else if(i==2 && _asx2!=null) _asx2.setWithDashedGrid(vb);
else if(_asy2!=null) _asy2.setWithDashedGrid(vb);
}
else if (name.endsWith("_AUTO")&& (value instanceof Boolean)) {
vb=((Boolean)value).booleanValue();
axesLimitsArray[i].auto=vb;
}
else if (name.endsWith("_LOG")&& (value instanceof Boolean)) {
vb=((Boolean)value).booleanValue();
if(i==0) logpx=vb; else if(i==1) logpy=vb;
else if(i==2) logsx=vb; else logsy=vb;
}
else if (name.endsWith("_MIN")&& (value instanceof Double)) {
vd=((Double)value).doubleValue();
axesLimitsArray[i].min=vd;
}
else if (name.endsWith("_MAX")&& (value instanceof Double)) {
vd=((Double)value).doubleValue();
axesLimitsArray[i].max=vd;
}
else if (name.endsWith("_STEP")&& (value instanceof Double)) {
vd=((Double)value).doubleValue();
if (vd >0.0)
axesLimitsArray[i].step=vd;
}
else if (name.endsWith("_LABEL")) {
if(value instanceof String) vs=(String)value; else vs=null;
axesLimitsArray[i].label=vs;
}
else if (name.endsWith("_FLOATING")) {
axesLimitsArray[i].floatingAxe = ((Boolean)value).booleanValue();
}
else if (name.endsWith("_FLOATING_RANGE")) {
if (value instanceof Double){
vd=((Double)value).doubleValue();
if ((vd >0.0) && axesLimitsArray[i].validity && axesLimitsArray[i].floatingAxe) {
axesLimitsArray[i].floatingAxeRange = vd;
}
}
}
}
}
}
else if ( (name.startsWith("PLOT_CURVE_LIST")) && (value instanceof Vector)){
Vector curves= new Vector();
if (primaryCurves!=null)
curves.addAll(primaryCurves);
if (secondaryCurves!=null)
curves.addAll(secondaryCurves);
if(!getCurveParametersList(curves).equals(value)){
setCurves((Vector)value);
}
}
else if ( (name.startsWith("PLOT_LIMIT_LIST")) && (value instanceof Vector)){
if(!getLimitParameters(_limits).equals(value)){
setLimitParamters((Vector)value);
}
}
}
public Object getPropertyValue(String name) {
Object res = super.getPropertyValue(name);
if (name.equalsIgnoreCase("PLOT_TITLE")) {
res=getTitle();
}
else if (name.equalsIgnoreCase("PLOT_LEGEND")) {
res=new Boolean(isLegendVisible());
}
else if (name.equalsIgnoreCase("PLOT_CURVE_INFORMATION")) {
res= isCurveInformationVisible();
}
else if(name.startsWith("PLOT_AXE_")){
for(int i=0;i<AXIS_ID.length;i++){
if(name.startsWith(AxisShape.getPrefix(AXIS_ID[i]))){
if (name.endsWith("_OK")) {
res=new Boolean(axesLimitsArray[i].validity);
}
else if (name.endsWith("_GRID")) {
if(i==0) res=new Boolean(_asx1!=null ? _asx1.isWithGridlines() : false);
else if(i==1) res=new Boolean(_asy1!=null ? _asy1.isWithGridlines() : false);
else if(i==2) res=new Boolean(_asx2!=null ? _asx2.isWithGridlines() : false);
else res=new Boolean(_asy2!=null ? _asy2.isWithGridlines() : false);
}else if (name.endsWith("_DASHEDGRID")) {
if(i==0) res=new Boolean(_asx1!=null ? _asx1.isWithDashedGrid() : false);
else if(i==1) res=new Boolean(_asy1!=null ? _asy1.isWithDashedGrid() : false);
else if(i==2) res=new Boolean(_asx2!=null ? _asx2.isWithDashedGrid() : false);
else res=new Boolean(_asy2!=null ? _asy2.isWithDashedGrid() : false);
}
else if (name.endsWith("_AUTO")) {
res=new Boolean(axesLimitsArray[i].auto);
}
else if (name.endsWith("_LOG")) {
if(i==0) res=new Boolean(logpx); else if(i==1) res=new Boolean(logpy);
else if(i==2) res=new Boolean(logsx); else res=new Boolean(logsy);
}
else if (name.endsWith("_MIN")) {
res=new Double(axesLimitsArray[i].min);
}
else if (name.endsWith("_MAX")) {
res=new Double(axesLimitsArray[i].max);
}
else if (name.endsWith("_STEP")) {
res=new Double(axesLimitsArray[i].step);
}
else if (name.endsWith("_LABEL")) {
res=axesLimitsArray[i].label;
}
else if (name.endsWith("_FLOATING")) {
res=new Boolean(axesLimitsArray[i].floatingAxe);
}
else if (name.endsWith("_FLOATING_RANGE")){
res= new Double(axesLimitsArray[i].floatingAxeRange);
}
}
}
}
else if (name.equalsIgnoreCase("PLOT_CURVE_LIST")){
Vector curves= new Vector();
if (primaryCurves!=null)
curves.addAll(primaryCurves);
if (secondaryCurves!=null)
curves.addAll(secondaryCurves);
res=getCurveParametersList(curves);
}
else if (name.equalsIgnoreCase("PLOT_LIMIT_LIST")){
res=getLimitParameters(_limits);
}
return res;
}
/**
* Get a list of curve parameter from the given list of curves
* @param curves - list of curves
* @return - list of curve parameter
*/
protected Vector getCurveParametersList(Vector curves){
Vector l=new Vector();
if(curves!=null){
for(int i=0;i<curves.size();i++){
CurveShape cs = (CurveShape) curves.get(i);
l.add(getCurveParameters(cs));
}
}
return l;
}
/**
* Get curve parameters from the curve shape
* @param cs - curve shape
* @return
*/
protected CurveParameters getCurveParameters(CurveShape cs){
CurveParameters res = createCurveParameters();
try{
res.xds=cs.getXSource();
}catch (DataException e){
res.xds=null;
}
try{
res.yds=cs.getYSource();
}catch (DataException e){
res.yds=null;
}
Curve c=getCurve(cs);
res.points=c.showPoints;
res.drawBars=c.drawBars;
res.strokeParams=new StrokeParameters(c.dashParam1 ,c.dashParam2);
res.color=c.color;
res.usePrimaryX= !c.secondaryXaxis;
res.usePrimaryY= !c.secondaryYaxis;
return res;
}
protected CurveParameters createCurveParameters(){
return new CurveParameters();
}
/**
* Create new curves using given list of curve parameters
* @param l - list of curve parameters
*/
public void setCurves(Vector l){
// Remove old curves
Vector oldCurves = (Vector)_curves.clone();
for(int i=0;i<oldCurves.size();i++){
removeCurve(((Curve)oldCurves.get(i)).shape);
}
// Add new curves
for(int i=0;i<l.size();i++){
CurvePropertiesPanel.CurveParameters cp=(CurvePropertiesPanel.CurveParameters)l.get(i);
CurveShape cs = doAddYAction(new Object[]{cp.yds, new Boolean(cp.usePrimaryY), new Boolean(cp.usePrimaryX)});
setCurve(getCurve(cs), cp);
}
}
/**
* Set a curve from given curve parameters
* @param c - curve to be set
* @param cp - curve parameters
*/
public void setCurve(Curve c, CurveParameters cp){
c.setShowPoints(cp.points);
c.setDrawBars(cp.drawBars);
c.setDashParameters(cp.strokeParams.param1,cp.strokeParams.param2);
c.color=cp.color;
}
protected Vector getLimitParameters(ArrayList al){
Vector l=new Vector();
if(al!=null){
for(int i=0;i<al.size();i++){
Limit c = (Limit) al.get(i);
LimitShape cs = c.shape;
LimitPropertiesPanel.LimitParameters cp=new LimitPropertiesPanel.LimitParameters(c.getLabel());
cp.strokeParams = new StrokeParameters(c.dashParam1 ,c.dashParam2);
cp.color=c.color;
cp.isVertical = cs.getIsVertical();
cp.secondaryAxis = c.secondaryAxis;
cp.position = cs.getPosition();
l.add(cp);
}
}
return l;
}
public void setLimitParamters(Vector l){
// clean previous
_limits.clear();
for(int i=0;i<l.size();i++){
LimitPropertiesPanel.LimitParameters cp=(LimitPropertiesPanel.LimitParameters)l.get(i);
LimitShape cs = doAddLimitAction(cp.isVertical, cp.secondaryAxis, cp.position, cp.name);
Limit c=getLimit(cs);
c.setLabel(cp.name);
c.secondaryAxis = cp.secondaryAxis;
c.setDashParameters(cp.strokeParams.param1,cp.strokeParams.param2);
c.color=cp.color;
}
}
/**
* Class AxeRange.
* Summary:
* This class represent an axe range, and contains
* properties for the axe.
*/
public static class AxeRange implements Serializable{
static final long serialVersionUID = 1147229299688184239L;
/** The min, max an step value of the axe.*/
public double min, max, step;
/** A boolean to know if the axe's range value are valid.*/
public boolean validity;
/** A boolean to keep the auto status.*/
public boolean auto;
/** The label to apply to the axe.*/
public String label;
/** A boolean to keep the floating property status.*/
public boolean floatingAxe;
/** Floating range value used when floatingAxe is enabled.*/
public double floatingAxeRange;
/**
* A boolean to know if AxeRange has been created by serialization while
* reading an old file where AxeRange did not exist, or created by a new version.
* AxeRange created by new Version has their created boolean to true.
*/
protected boolean created = false;
/**
* Constructor AxeRange.
*/
public AxeRange(){
created = true;
//Set auto scale to true, as default behavior.
auto = true;
floatingAxe = false;
floatingAxeRange = 1000.0;
}
/**
* Constructor AxeRange.
* @param _min The min value of the axe.
* @param _max The max value of the axe.
* @param _step The step value of the axe.
* @param _validity A boolean to know if the axe's range value are valid.
* @param _auto A boolean to keep the auto status
* @param _label The label to apply to the axe
*/
public AxeRange(double _min, double _max, double _step, boolean _validity, boolean _auto, String _label, boolean _floatingAxe, double _floatingAxeRange){
created = true;
//set attributes.
min=_min;
max=_max;
step=_step;
validity=_validity;
auto=_auto;
label=_label;
floatingAxe = _floatingAxe;
floatingAxeRange = _floatingAxeRange;
}
public AxeRange(double _min, double _max, double _step, boolean _validity, boolean _auto, String _label){
this(_min,_max,_step,_validity,_auto,_label,false,0.0);
}
/**
* Method <b>set</b>
* <br><b>Summary:</b><br>
* This method sets some axe range values.
* Parameters:
* @param _min The min value of the axe.
* @param _max The max value of the axe.
* @param _step The step value of the axe.
* @param _validity A boolean to know if the axe's range value are valid.
*
*/
public void set(double _min, double _max, double _step, boolean _validity) {
//set attributes.
min = _min;
max = _max;
step = _step;
validity = _validity;
}
/**
* Method <b>computeStep</b>
* <br><b>Summary:</b><br>
* This method compute the step to apply to the axeRange.
* Parameters:
* @param nbGraduation The numberOfGraduation to apply.
*
*/
public void computeStep(int nbGraduation) {
//If min and max are equals, increase interval to have correct step/min/max values.
if(min == max){
min--;
max++;
}
step = Plot.computeStep(min, max,nbGraduation);
validity = true; // no exception at this point => OK
}
}
/* (non-Javadoc)
* @see simtools.diagram.DiagramComponent.ContextualDrawingProvider#getContextualDrawing()
*/
public ContextualDrawing getContextualDrawing(DiagramSelection s) {
return new PlotZoom(s);
}
public class PlotCompoundEdit extends CompoundEdit{
public PlotCompoundEdit(){
}
public PlotCompoundEdit(HashMap oldValues){
Iterator it=oldValues.keySet().iterator();
while(it.hasNext()){
String n=(String)it.next();
addEdit(new PropertyChangeEdit(Plot.this, n, oldValues.get(n),getPropertyValue(n)));
}
end();
}
/* (non-Javadoc)
* @see javax.swing.undo.CompoundEdit#redo()
*/
public void redo() throws CannotRedoException {
super.redo();
repaintDiagram(getBounds());
}
/* (non-Javadoc)
* @see javax.swing.undo.CompoundEdit#undo()
*/
public void undo() throws CannotUndoException {
super.undo();
repaintDiagram(getBounds());
}
};
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#update()
*/
public void refresh(){
super.refresh();
repaintDiagram(getBounds());
}
}